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_HTMLEditor_h
7 #define mozilla_HTMLEditor_h
8 
9 #include "mozilla/Attributes.h"
10 #include "mozilla/ComposerCommandsUpdater.h"
11 #include "mozilla/CSSEditUtils.h"
12 #include "mozilla/EditorUtils.h"
13 #include "mozilla/ManualNAC.h"
14 #include "mozilla/Result.h"
15 #include "mozilla/TextEditor.h"
16 #include "mozilla/UniquePtr.h"
17 #include "mozilla/dom/Element.h"
18 #include "mozilla/dom/File.h"
19 
20 #include "nsAttrName.h"
21 #include "nsCOMPtr.h"
22 #include "nsIDocumentObserver.h"
23 #include "nsIDOMEventListener.h"
24 #include "nsIEditorMailSupport.h"
25 #include "nsIHTMLAbsPosEditor.h"
26 #include "nsIHTMLEditor.h"
27 #include "nsIHTMLInlineTableEditor.h"
28 #include "nsIHTMLObjectResizer.h"
29 #include "nsITableEditor.h"
30 #include "nsPoint.h"
31 #include "nsStubMutationObserver.h"
32 #include "nsTArray.h"
33 
34 class nsDocumentFragment;
35 class nsHTMLDocument;
36 class nsITransferable;
37 class nsIClipboard;
38 class nsRange;
39 class nsStaticAtom;
40 class nsTableWrapperFrame;
41 
42 namespace mozilla {
43 class AlignStateAtSelection;
44 class AutoSelectionSetterAfterTableEdit;
45 class AutoSetTemporaryAncestorLimiter;
46 class EditActionResult;
47 class EditResult;
48 class EmptyEditableFunctor;
49 class JoinNodeTransaction;
50 class ListElementSelectionState;
51 class ListItemElementSelectionState;
52 class MoveNodeResult;
53 class ParagraphStateAtSelection;
54 class ResizerSelectionListener;
55 class Runnable;
56 class SplitNodeTransaction;
57 class SplitRangeOffFromNodeResult;
58 class SplitRangeOffResult;
59 class WSRunObject;
60 class WSRunScanner;
61 class WSScanResult;
62 enum class EditSubAction : int32_t;
63 struct PropItem;
64 template <class T>
65 class OwningNonNull;
66 namespace dom {
67 class AbstractRange;
68 class Blob;
69 class DocumentFragment;
70 class Event;
71 class MouseEvent;
72 class StaticRange;
73 }  // namespace dom
74 namespace widget {
75 struct IMEState;
76 }  // namespace widget
77 
78 enum class ParagraphSeparator { div, p, br };
79 
80 /**
81  * The HTML editor implementation.<br>
82  * Use to edit HTML document represented as a DOM tree.
83  */
84 class HTMLEditor final : public TextEditor,
85                          public nsIHTMLEditor,
86                          public nsIHTMLObjectResizer,
87                          public nsIHTMLAbsPosEditor,
88                          public nsITableEditor,
89                          public nsIHTMLInlineTableEditor,
90                          public nsStubMutationObserver,
91                          public nsIEditorMailSupport {
92  public:
93   /****************************************************************************
94    * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
95    *       classes under libeditor except EditorEventListener and
96    *       HTMLEditorEventListener because each public method which may fire
97    *       eEditorInput event will need to instantiate new stack class for
98    *       managing input type value of eEditorInput and cache some objects
99    *       for smarter handling.  In other words, when you add new root
100    *       method to edit the DOM tree, you can make your new method public.
101    ****************************************************************************/
102 
103   NS_DECL_ISUPPORTS_INHERITED
104   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditor, TextEditor)
105 
106   // nsStubMutationObserver overrides
107   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
108   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
109   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
110 
111   // nsIHTMLEditor methods
112   NS_DECL_NSIHTMLEDITOR
113 
114   // nsIHTMLObjectResizer methods (implemented in HTMLObjectResizer.cpp)
115   NS_DECL_NSIHTMLOBJECTRESIZER
116 
117   // nsIHTMLAbsPosEditor methods (implemented in HTMLAbsPositionEditor.cpp)
118   NS_DECL_NSIHTMLABSPOSEDITOR
119 
120   // nsIHTMLInlineTableEditor methods (implemented in HTMLInlineTableEditor.cpp)
121   NS_DECL_NSIHTMLINLINETABLEEDITOR
122 
123   // nsIEditorMailSupport methods
124   NS_DECL_NSIEDITORMAILSUPPORT
125 
126   // nsITableEditor methods
127   NS_DECL_NSITABLEEDITOR
128 
129   // nsISelectionListener overrides
130   NS_DECL_NSISELECTIONLISTENER
131 
132   HTMLEditor();
133 
134   nsHTMLDocument* GetHTMLDocument() const;
135 
136   MOZ_CAN_RUN_SCRIPT virtual void PreDestroy(bool aDestroyingFrames) override;
137 
138   bool GetReturnInParagraphCreatesNewParagraph();
139 
140   // TextEditor overrides
141   MOZ_CAN_RUN_SCRIPT virtual nsresult Init(Document& aDoc, Element* aRoot,
142                                            nsISelectionController* aSelCon,
143                                            uint32_t aFlags,
144                                            const nsAString& aValue) override;
145   MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD BeginningOfDocument() override;
146   NS_IMETHOD SetFlags(uint32_t aFlags) override;
147 
148   /**
149    * IsEmpty() checks whether the editor is empty.  If editor has only padding
150    * <br> element for empty editor, returns true.  If editor's root element has
151    * non-empty text nodes or other nodes like <br>, returns false even if there
152    * are only empty blocks.
153    */
154   virtual bool IsEmpty() const override;
155 
156   virtual bool CanPaste(int32_t aClipboardType) const override;
157   using EditorBase::CanPaste;
158 
159   MOZ_CAN_RUN_SCRIPT virtual nsresult PasteTransferableAsAction(
160       nsITransferable* aTransferable,
161       nsIPrincipal* aPrincipal = nullptr) override;
162 
163   MOZ_CAN_RUN_SCRIPT NS_IMETHOD DeleteNode(nsINode* aNode) override;
164 
165   MOZ_CAN_RUN_SCRIPT NS_IMETHOD InsertLineBreak() override;
166 
167   MOZ_CAN_RUN_SCRIPT virtual nsresult HandleKeyPressEvent(
168       WidgetKeyboardEvent* aKeyboardEvent) override;
169   virtual nsIContent* GetFocusedContent() const override;
170   virtual nsIContent* GetFocusedContentForIME() const override;
171   virtual bool IsActiveInDOMWindow() const override;
172   virtual dom::EventTarget* GetDOMEventTarget() const override;
173   virtual Element* FindSelectionRoot(nsINode* aNode) const override;
174   virtual bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) override;
175   virtual nsresult GetPreferredIMEState(widget::IMEState* aState) override;
176 
177   /**
178    * GetBackgroundColorState() returns what the background color of the
179    * selection.
180    *
181    * @param aMixed      true if there is more than one font color
182    * @param aOutColor   Color string. "" is returned for none.
183    */
184   MOZ_CAN_RUN_SCRIPT nsresult GetBackgroundColorState(bool* aMixed,
185                                                       nsAString& aOutColor);
186 
187   /**
188    * PasteNoFormatting() pastes content in clipboard without any style
189    * information.
190    *
191    * @param aSelectionType      nsIClipboard::kGlobalClipboard or
192    *                            nsIClipboard::kSelectionClipboard.
193    * @param aPrincipal          Set subject principal if it may be called by
194    *                            JS.  If set to nullptr, will be treated as
195    *                            called by system.
196    */
197   MOZ_CAN_RUN_SCRIPT nsresult PasteNoFormattingAsAction(
198       int32_t aSelectionType, nsIPrincipal* aPrincipal = nullptr);
199 
200   /**
201    * PasteAsQuotationAsAction() pastes content in clipboard with newly created
202    * blockquote element.  If the editor is in plaintext mode, will paste the
203    * content with appending ">" to start of each line.
204    *
205    * @param aClipboardType      nsIClipboard::kGlobalClipboard or
206    *                            nsIClipboard::kSelectionClipboard.
207    * @param aDispatchPasteEvent true if this should dispatch ePaste event
208    *                            before pasting.  Otherwise, false.
209    * @param aPrincipal          Set subject principal if it may be called by
210    *                            JS.  If set to nullptr, will be treated as
211    *                            called by system.
212    */
213   MOZ_CAN_RUN_SCRIPT virtual nsresult PasteAsQuotationAsAction(
214       int32_t aClipboardType, bool aDispatchPasteEvent,
215       nsIPrincipal* aPrincipal = nullptr) override;
216 
217   /**
218    * Can we paste |aTransferable| or, if |aTransferable| is null, will a call
219    * to pasteTransferable later possibly succeed if given an instance of
220    * nsITransferable then? True if the doc is modifiable, and, if
221    * |aTransfeable| is non-null, we have pasteable data in |aTransfeable|.
222    */
223   virtual bool CanPasteTransferable(nsITransferable* aTransferable) override;
224 
225   /**
226    * InsertLineBreakAsAction() is called when user inputs a line break with
227    * Shift + Enter or something.
228    *
229    * @param aPrincipal          Set subject principal if it may be called by
230    *                            JS.  If set to nullptr, will be treated as
231    *                            called by system.
232    */
233   MOZ_CAN_RUN_SCRIPT virtual nsresult InsertLineBreakAsAction(
234       nsIPrincipal* aPrincipal = nullptr) override;
235 
236   /**
237    * InsertParagraphSeparatorAsAction() is called when user tries to separate
238    * current paragraph with Enter key press in HTMLEditor or something.
239    *
240    * @param aPrincipal          Set subject principal if it may be called by
241    *                            JS.  If set to nullptr, will be treated as
242    *                            called by system.
243    */
244   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
245   InsertParagraphSeparatorAsAction(nsIPrincipal* aPrincipal = nullptr);
246 
247   MOZ_CAN_RUN_SCRIPT nsresult
248   InsertElementAtSelectionAsAction(Element* aElement, bool aDeleteSelection,
249                                    nsIPrincipal* aPrincipal = nullptr);
250 
251   MOZ_CAN_RUN_SCRIPT nsresult InsertLinkAroundSelectionAsAction(
252       Element* aAnchorElement, nsIPrincipal* aPrincipal = nullptr);
253 
254   /**
255    * CreateElementWithDefaults() creates new element whose name is
256    * aTagName with some default attributes are set.  Note that this is a
257    * public utility method.  I.e., just creates element, not insert it
258    * into the DOM tree.
259    * NOTE: This is available for internal use too since this does not change
260    *       the DOM tree nor undo transactions, and does not refer Selection,
261    *       etc.
262    *
263    * @param aTagName            The new element's tag name.  If the name is
264    *                            one of "href", "anchor" or "namedanchor",
265    *                            this creates an <a> element.
266    * @return                    Newly created element.
267    */
268   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> CreateElementWithDefaults(
269       const nsAtom& aTagName);
270 
271   /**
272    * Indent or outdent content around Selection.
273    *
274    * @param aPrincipal          Set subject principal if it may be called by
275    *                            JS.  If set to nullptr, will be treated as
276    *                            called by system.
277    */
278   MOZ_CAN_RUN_SCRIPT nsresult
279   IndentAsAction(nsIPrincipal* aPrincipal = nullptr);
280   MOZ_CAN_RUN_SCRIPT nsresult
281   OutdentAsAction(nsIPrincipal* aPrincipal = nullptr);
282 
283   MOZ_CAN_RUN_SCRIPT nsresult SetParagraphFormatAsAction(
284       const nsAString& aParagraphFormat, nsIPrincipal* aPrincipal = nullptr);
285 
286   MOZ_CAN_RUN_SCRIPT nsresult AlignAsAction(const nsAString& aAlignType,
287                                             nsIPrincipal* aPrincipal = nullptr);
288 
289   MOZ_CAN_RUN_SCRIPT nsresult RemoveListAsAction(
290       const nsAString& aListType, nsIPrincipal* aPrincipal = nullptr);
291 
292   /**
293    * MakeOrChangeListAsAction() makes selected hard lines list element(s).
294    *
295    * @param aListElementTagName         The new list element tag name.  Must be
296    *                                    nsGkAtoms::ul, nsGkAtoms::ol or
297    *                                    nsGkAtoms::dl.
298    * @param aBulletType                 If this is not empty string, it's set
299    *                                    to `type` attribute of new list item
300    *                                    elements.  Otherwise, existing `type`
301    *                                    attributes will be removed.
302    * @param aSelectAllOfCurrentList     Yes if this should treat all of
303    *                                    ancestor list element at selection.
304    */
305   enum class SelectAllOfCurrentList { Yes, No };
306   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MakeOrChangeListAsAction(
307       nsAtom& aListElementTagName, const nsAString& aBulletType,
308       SelectAllOfCurrentList aSelectAllOfCurrentList,
309       nsIPrincipal* aPrincipal = nullptr);
310 
311   /**
312    * event callback when a mouse button is pressed
313    * @param aX      [IN] horizontal position of the pointer
314    * @param aY      [IN] vertical position of the pointer
315    * @param aTarget [IN] the element triggering the event
316    * @param aMouseEvent [IN] the event
317    */
318   MOZ_CAN_RUN_SCRIPT nsresult OnMouseDown(int32_t aX, int32_t aY,
319                                           Element* aTarget,
320                                           dom::Event* aMouseEvent);
321 
322   /**
323    * event callback when a mouse button is released
324    * @param aX      [IN] horizontal position of the pointer
325    * @param aY      [IN] vertical position of the pointer
326    */
327   MOZ_CAN_RUN_SCRIPT nsresult OnMouseUp(int32_t aX, int32_t aY);
328 
329   /**
330    * event callback when the mouse pointer is moved
331    * @param aMouseEvent [IN] the event
332    */
333   MOZ_CAN_RUN_SCRIPT nsresult OnMouseMove(dom::MouseEvent* aMouseEvent);
334 
335   /**
336    * IsCSSEnabled() returns true if this editor treats styles with style
337    * attribute of HTML elements.  Otherwise, if this editor treats all styles
338    * with "font style elements" like <b>, <i>, etc, and <blockquote> to indent,
339    * align attribute to align contents, returns false.
340    */
IsCSSEnabled()341   bool IsCSSEnabled() const {
342     // TODO: removal of mCSSAware and use only the presence of mCSSEditUtils
343     return mCSSAware && mCSSEditUtils && mCSSEditUtils->IsCSSPrefChecked();
344   }
345 
346   /**
347    * Enable/disable object resizers for <img> elements, <table> elements,
348    * absolute positioned elements (required absolute position editor enabled).
349    */
EnableObjectResizer(bool aEnable)350   MOZ_CAN_RUN_SCRIPT void EnableObjectResizer(bool aEnable) {
351     if (mIsObjectResizingEnabled == aEnable) {
352       return;
353     }
354 
355     AutoEditActionDataSetter editActionData(
356         *this, EditAction::eEnableOrDisableResizer);
357     if (NS_WARN_IF(!editActionData.CanHandle())) {
358       return;
359     }
360 
361     mIsObjectResizingEnabled = aEnable;
362     RefreshEditingUI();
363   }
IsObjectResizerEnabled()364   bool IsObjectResizerEnabled() const { return mIsObjectResizingEnabled; }
365 
GetResizerTarget()366   Element* GetResizerTarget() const { return mResizedObject; }
367 
368   /**
369    * Enable/disable inline table editor, e.g., adding new row or column,
370    * removing existing row or column.
371    */
EnableInlineTableEditor(bool aEnable)372   MOZ_CAN_RUN_SCRIPT void EnableInlineTableEditor(bool aEnable) {
373     if (mIsInlineTableEditingEnabled == aEnable) {
374       return;
375     }
376 
377     AutoEditActionDataSetter editActionData(
378         *this, EditAction::eEnableOrDisableInlineTableEditingUI);
379     if (NS_WARN_IF(!editActionData.CanHandle())) {
380       return;
381     }
382 
383     mIsInlineTableEditingEnabled = aEnable;
384     RefreshEditingUI();
385   }
IsInlineTableEditorEnabled()386   bool IsInlineTableEditorEnabled() const {
387     return mIsInlineTableEditingEnabled;
388   }
389 
390   /**
391    * Enable/disable absolute position editor, resizing absolute positioned
392    * elements (required object resizers enabled) or positioning them with
393    * dragging grabber.
394    */
EnableAbsolutePositionEditor(bool aEnable)395   MOZ_CAN_RUN_SCRIPT void EnableAbsolutePositionEditor(bool aEnable) {
396     if (mIsAbsolutelyPositioningEnabled == aEnable) {
397       return;
398     }
399 
400     AutoEditActionDataSetter editActionData(
401         *this, EditAction::eEnableOrDisableAbsolutePositionEditor);
402     if (NS_WARN_IF(!editActionData.CanHandle())) {
403       return;
404     }
405 
406     mIsAbsolutelyPositioningEnabled = aEnable;
407     RefreshEditingUI();
408   }
IsAbsolutePositionEditorEnabled()409   bool IsAbsolutePositionEditorEnabled() const {
410     return mIsAbsolutelyPositioningEnabled;
411   }
412 
413   // non-virtual methods of interface methods
414 
415   /**
416    * returns the deepest absolutely positioned container of the selection
417    * if it exists or null.
418    */
419   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element>
420   GetAbsolutelyPositionedSelectionContainer() const;
421 
GetPositionedElement()422   Element* GetPositionedElement() const { return mAbsolutelyPositionedObject; }
423 
424   /**
425    * extracts the selection from the normal flow of the document and
426    * positions it.
427    *
428    * @param aEnabled [IN] true to absolutely position the selection,
429    *                      false to put it back in the normal flow
430    * @param aPrincipal          Set subject principal if it may be called by
431    *                            JS.  If set to nullptr, will be treated as
432    *                            called by system.
433    */
434   MOZ_CAN_RUN_SCRIPT nsresult SetSelectionToAbsoluteOrStaticAsAction(
435       bool aEnabled, nsIPrincipal* aPrincipal = nullptr);
436 
437   /**
438    * returns the absolute z-index of a positioned element. Never returns 'auto'
439    * @return         the z-index of the element
440    * @param aElement [IN] the element.
441    */
442   MOZ_CAN_RUN_SCRIPT int32_t GetZIndex(Element& aElement);
443 
444   /**
445    * adds aChange to the z-index of the currently positioned element.
446    *
447    * @param aChange [IN] relative change to apply to current z-index
448    * @param aPrincipal          Set subject principal if it may be called by
449    *                            JS.  If set to nullptr, will be treated as
450    *                            called by system.
451    */
452   MOZ_CAN_RUN_SCRIPT nsresult
453   AddZIndexAsAction(int32_t aChange, nsIPrincipal* aPrincipal = nullptr);
454 
455   MOZ_CAN_RUN_SCRIPT nsresult SetBackgroundColorAsAction(
456       const nsAString& aColor, nsIPrincipal* aPrincipal = nullptr);
457 
458   /**
459    * SetInlinePropertyAsAction() sets a property which changes inline style of
460    * text.  E.g., bold, italic, super and sub.
461    * This automatically removes exclusive style, however, treats all changes
462    * as a transaction.
463    *
464    * @param aPrincipal          Set subject principal if it may be called by
465    *                            JS.  If set to nullptr, will be treated as
466    *                            called by system.
467    */
468   MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertyAsAction(
469       nsAtom& aProperty, nsAtom* aAttribute, const nsAString& aValue,
470       nsIPrincipal* aPrincipal = nullptr);
471 
472   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlineProperty(
473       nsAtom* aHTMLProperty, nsAtom* aAttribute, const nsAString& aValue,
474       bool* aFirst, bool* aAny, bool* aAll) const;
475   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlinePropertyWithAttrValue(
476       nsAtom* aHTMLProperty, nsAtom* aAttribute, const nsAString& aValue,
477       bool* aFirst, bool* aAny, bool* aAll, nsAString& outValue);
478 
479   /**
480    * RemoveInlinePropertyAsAction() removes a property which changes inline
481    * style of text.  E.g., bold, italic, super and sub.
482    *
483    * @param aHTMLProperty   Tag name whcih represents the inline style you want
484    *                        to remove.  E.g., nsGkAtoms::strong, nsGkAtoms::b,
485    *                        etc.  If nsGkAtoms::href, <a> element which has
486    *                        href attribute will be removed.
487    *                        If nsGkAtoms::name, <a> element which has non-empty
488    *                        name attribute will be removed.
489    * @param aAttribute  If aHTMLProperty is nsGkAtoms::font, aAttribute should
490    *                    be nsGkAtoms::fase, nsGkAtoms::size, nsGkAtoms::color
491    *                    or nsGkAtoms::bgcolor.  Otherwise, set nullptr.
492    *                    Must not use nsGkAtoms::_empty here.
493    * @param aPrincipal  Set subject principal if it may be called by JS.  If
494    *                    set to nullptr, will be treated as called by system.
495    */
496   MOZ_CAN_RUN_SCRIPT nsresult RemoveInlinePropertyAsAction(
497       nsStaticAtom& aHTMLProperty, nsStaticAtom* aAttribute,
498       nsIPrincipal* aPrincipal = nullptr);
499 
500   MOZ_CAN_RUN_SCRIPT nsresult
501   RemoveAllInlinePropertiesAsAction(nsIPrincipal* aPrincipal = nullptr);
502 
503   MOZ_CAN_RUN_SCRIPT nsresult
504   IncreaseFontSizeAsAction(nsIPrincipal* aPrincipal = nullptr);
505 
506   MOZ_CAN_RUN_SCRIPT nsresult
507   DecreaseFontSizeAsAction(nsIPrincipal* aPrincipal = nullptr);
508 
509   /**
510    * GetFontColorState() returns foreground color information in first
511    * range of Selection.
512    * If first range of Selection is collapsed and there is a cache of style for
513    * new text, aIsMixed is set to false and aColor is set to the cached color.
514    * If first range of Selection is collapsed and there is no cached color,
515    * this returns the color of the node, aIsMixed is set to false and aColor is
516    * set to the color.
517    * If first range of Selection is not collapsed, this collects colors of
518    * each node in the range.  If there are two or more colors, aIsMixed is set
519    * to true and aColor is truncated.  If only one color is set to all of the
520    * range, aIsMixed is set to false and aColor is set to the color.
521    * If there is no Selection ranges, aIsMixed is set to false and aColor is
522    * truncated.
523    *
524    * @param aIsMixed            Must not be nullptr.  This is set to true
525    *                            if there is two or more colors in first
526    *                            range of Selection.
527    * @param aColor              Returns the color if only one color is set to
528    *                            all of first range in Selection.  Otherwise,
529    *                            returns empty string.
530    * @return                    Returns error only when illegal cases, e.g.,
531    *                            Selection instance has gone, first range
532    *                            Selection is broken.
533    */
534   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
535   GetFontColorState(bool* aIsMixed, nsAString& aColor);
536 
537   /**
538    * SetComposerCommandsUpdater() sets or unsets mComposerCommandsUpdater.
539    * This will crash in debug build if the editor already has an instance
540    * but called with another instance.
541    */
SetComposerCommandsUpdater(ComposerCommandsUpdater * aComposerCommandsUpdater)542   void SetComposerCommandsUpdater(
543       ComposerCommandsUpdater* aComposerCommandsUpdater) {
544     MOZ_ASSERT(!aComposerCommandsUpdater || !mComposerCommandsUpdater ||
545                aComposerCommandsUpdater == mComposerCommandsUpdater);
546     mComposerCommandsUpdater = aComposerCommandsUpdater;
547   }
548 
DefaultParagraphSeparatorTagName()549   nsStaticAtom& DefaultParagraphSeparatorTagName() const {
550     return HTMLEditor::ToParagraphSeparatorTagName(mDefaultParagraphSeparator);
551   }
GetDefaultParagraphSeparator()552   ParagraphSeparator GetDefaultParagraphSeparator() const {
553     return mDefaultParagraphSeparator;
554   }
SetDefaultParagraphSeparator(ParagraphSeparator aSep)555   void SetDefaultParagraphSeparator(ParagraphSeparator aSep) {
556     mDefaultParagraphSeparator = aSep;
557   }
ToParagraphSeparatorTagName(ParagraphSeparator aSeparator)558   static nsStaticAtom& ToParagraphSeparatorTagName(
559       ParagraphSeparator aSeparator) {
560     switch (aSeparator) {
561       case ParagraphSeparator::div:
562         return *nsGkAtoms::div;
563       case ParagraphSeparator::p:
564         return *nsGkAtoms::p;
565       case ParagraphSeparator::br:
566         return *nsGkAtoms::br;
567       default:
568         MOZ_ASSERT_UNREACHABLE("New paragraph separator isn't handled here");
569         return *nsGkAtoms::div;
570     }
571   }
572 
573   /**
574    * Modifies the table containing the selection according to the
575    * activation of an inline table editing UI element
576    * @param aUIAnonymousElement [IN] the inline table editing UI element
577    */
578   MOZ_CAN_RUN_SCRIPT nsresult
579   DoInlineTableEditingAction(const Element& aUIAnonymousElement);
580 
581   /**
582    * GetInclusiveAncestorByTagName() looks for an element node whose name
583    * matches aTagName from aNode or anchor node of Selection to <body> element.
584    *
585    * @param aTagName        The tag name which you want to look for.
586    *                        Must not be nsGkAtoms::_empty.
587    *                        If nsGkAtoms::list, the result may be <ul>, <ol> or
588    *                        <dl> element.
589    *                        If nsGkAtoms::td, the result may be <td> or <th>.
590    *                        If nsGkAtoms::href, the result may be <a> element
591    *                        which has "href" attribute with non-empty value.
592    *                        If nsGkAtoms::anchor, the result may be <a> which
593    *                        has "name" attribute with non-empty value.
594    * @param aContent        Start node to look for the result.
595    * @return                If an element which matches aTagName, returns
596    *                        an Element.  Otherwise, nullptr.
597    */
598   Element* GetInclusiveAncestorByTagName(const nsStaticAtom& aTagName,
599                                          nsIContent& aContent) const;
600 
601   /**
602    * Get an active editor's editing host in DOM window.  If this editor isn't
603    * active in the DOM window, this returns NULL.
604    */
605   Element* GetActiveEditingHost() const;
606 
607   /**
608    * Retruns true if we're in designMode.
609    */
IsInDesignMode()610   bool IsInDesignMode() const {
611     Document* document = GetDocument();
612     return document && document->HasFlag(NODE_IS_EDITABLE);
613   }
614 
615   /**
616    * NotifyEditingHostMaybeChanged() is called when new element becomes
617    * contenteditable when the document already had contenteditable elements.
618    */
619   void NotifyEditingHostMaybeChanged();
620 
621   /** Insert a string as quoted text
622    * (whose representation is dependant on the editor type),
623    * replacing the selected text (if any).
624    *
625    * @param aQuotedText    The actual text to be quoted
626    * @parem aNodeInserted  Return the node which was inserted.
627    */
628   MOZ_CAN_RUN_SCRIPT  // USED_BY_COMM_CENTRAL
629       nsresult
630       InsertAsQuotation(const nsAString& aQuotedText, nsINode** aNodeInserted);
631 
632   /**
633    * Inserts a plaintext string at the current location,
634    * with special processing for lines beginning with ">",
635    * which will be treated as mail quotes and inserted
636    * as plaintext quoted blocks.
637    * If the selection is not collapsed, the selection is deleted
638    * and the insertion takes place at the resulting collapsed selection.
639    *
640    * @param aString   the string to be inserted
641    */
642   MOZ_CAN_RUN_SCRIPT nsresult
643   InsertTextWithQuotations(const nsAString& aStringToInsert);
644 
645   MOZ_CAN_RUN_SCRIPT nsresult InsertHTMLAsAction(
646       const nsAString& aInString, nsIPrincipal* aPrincipal = nullptr);
647 
648  protected:  // May be called by friends.
649   /****************************************************************************
650    * Some friend classes are allowed to call the following protected methods.
651    * However, those methods won't prepare caches of some objects which are
652    * necessary for them.  So, if you call them from friend classes, you need
653    * to make sure that AutoEditActionDataSetter is created.
654    ****************************************************************************/
655 
656   /**
657    * InsertBRElementWithTransaction() creates a <br> element and inserts it
658    * before aPointToInsert.  Then, tries to collapse selection at or after the
659    * new <br> node if aSelect is not eNone.
660    *
661    * @param aPointToInsert      The DOM point where should be <br> node inserted
662    *                            before.
663    * @param aSelect             If eNone, this won't change selection.
664    *                            If eNext, selection will be collapsed after
665    *                            the <br> element.
666    *                            If ePrevious, selection will be collapsed at
667    *                            the <br> element.
668    * @return                    The new <br> node.  If failed to create new
669    *                            <br> node, returns nullptr.
670    */
671   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> InsertBRElementWithTransaction(
672       const EditorDOMPoint& aPointToInsert, EDirection aSelect = eNone);
673 
674   /**
675    * DeleteNodeWithTransaction() removes aContent from the DOM tree if it's
676    * modifiable.  Note that this is not an override of same method of
677    * EditorBase.
678    *
679    * @param aContent    The node to be removed from the DOM tree.
680    */
681   MOZ_CAN_RUN_SCRIPT nsresult DeleteNodeWithTransaction(nsIContent& aContent);
682 
683   /**
684    * DeleteTextWithTransaction() removes text in the range from aTextNode if
685    * it's modifiable.  Note that this not an override of same method of
686    * EditorBase.
687    *
688    * @param aTextNode           The text node which should be modified.
689    * @param aOffset             Start offset of removing text in aTextNode.
690    * @param aLength             Length of removing text.
691    */
692   MOZ_CAN_RUN_SCRIPT nsresult DeleteTextWithTransaction(dom::Text& aTextNode,
693                                                         uint32_t aOffset,
694                                                         uint32_t aLength);
695 
696   /**
697    * ReplaceTextWithTransaction() replaces text in the range with
698    * aStringToInsert.
699    */
700   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ReplaceTextWithTransaction(
701       dom::Text& aTextNode, uint32_t aOffset, uint32_t aLength,
702       const nsAString& aStringToInsert);
703 
704   /**
705    * DeleteParentBlocksIfEmpty() removes parent block elements if they
706    * don't have visible contents.  Note that due performance issue of
707    * WSRunObject, this call may be expensive.  And also note that this
708    * removes a empty block with a transaction.  So, please make sure that
709    * you've already created `AutoPlaceholderBatch`.
710    *
711    * @param aPoint      The point whether this method climbing up the DOM
712    *                    tree to remove empty parent blocks.
713    * @return            NS_OK if one or more empty block parents are deleted.
714    *                    NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND if the point is
715    *                    not in empty block.
716    *                    Or NS_ERROR_* if something unexpected occurs.
717    */
718   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
719   DeleteParentBlocksWithTransactionIfEmpty(const EditorDOMPoint& aPoint);
720 
721   /**
722    * InsertTextWithTransaction() inserts aStringToInsert at aPointToInsert.
723    */
724   MOZ_CAN_RUN_SCRIPT virtual nsresult InsertTextWithTransaction(
725       Document& aDocument, const nsAString& aStringToInsert,
726       const EditorRawDOMPoint& aPointToInsert,
727       EditorRawDOMPoint* aPointAfterInsertedString = nullptr) override;
728 
729   /**
730    * CopyLastEditableChildStyles() clones inline container elements into
731    * aPreviousBlock to aNewBlock to keep using same style in it.
732    *
733    * @param aPreviousBlock      The previous block element.  All inline
734    *                            elements which are last sibling of each level
735    *                            are cloned to aNewBlock.
736    * @param aNewBlock           New block container element.
737    * @param aNewBRElement       If this method creates a new <br> element for
738    *                            placeholder, this is set to the new <br>
739    *                            element.
740    */
741   MOZ_CAN_RUN_SCRIPT nsresult CopyLastEditableChildStylesWithTransaction(
742       Element& aPreviousBlock, Element& aNewBlock,
743       RefPtr<Element>* aNewBRElement);
744 
745   /**
746    * RemoveBlockContainerWithTransaction() removes aElement from the DOM tree
747    * but moves its all children to its parent node and if its parent needs <br>
748    * element to have at least one line-height, this inserts <br> element
749    * automatically.
750    *
751    * @param aElement            Block element to be removed.
752    */
753   MOZ_CAN_RUN_SCRIPT nsresult
754   RemoveBlockContainerWithTransaction(Element& aElement);
755 
756   virtual Element* GetEditorRoot() const override;
757   MOZ_CAN_RUN_SCRIPT virtual nsresult RemoveAttributeOrEquivalent(
758       Element* aElement, nsAtom* aAttribute,
759       bool aSuppressTransaction) override;
760   MOZ_CAN_RUN_SCRIPT virtual nsresult SetAttributeOrEquivalent(
761       Element* aElement, nsAtom* aAttribute, const nsAString& aValue,
762       bool aSuppressTransaction) override;
763   using EditorBase::RemoveAttributeOrEquivalent;
764   using EditorBase::SetAttributeOrEquivalent;
765 
766   /**
767    * Returns container element of ranges in Selection.  If Selection is
768    * collapsed, returns focus container node (or its parent element).
769    * If Selection selects only one element node, returns the element node.
770    * If Selection is only one range, returns common ancestor of the range.
771    * XXX If there are two or more Selection ranges, this returns parent node
772    *     of start container of a range which starts with different node from
773    *     start container of the first range.
774    */
775   Element* GetSelectionContainerElement() const;
776 
777   /**
778    * GetFirstSelectedTableCellElement() returns a <td> or <th> element if
779    * first range of Selection (i.e., result of Selection::GetRangeAt(0))
780    * selects a <td> element or <th> element.  Even if Selection is in
781    * a cell element, this returns nullptr.  And even if 2nd or later
782    * range of Selection selects a cell element, also returns nullptr.
783    * Note that when this looks for a cell element, this resets the internal
784    * index of ranges of Selection.  When you call
785    * GetNextSelectedTableCellElement() after a call of this, it'll return 2nd
786    * selected cell if there is.
787    *
788    * @param aRv                 Returns error if there is no selection or
789    *                            first range of Selection is unexpected.
790    * @return                    A <td> or <th> element is selected by first
791    *                            range of Selection.  Note that the range must
792    *                            be: startContaienr and endContainer are same
793    *                            <tr> element, startOffset + 1 equals endOffset.
794    */
795   already_AddRefed<Element> GetFirstSelectedTableCellElement(
796       ErrorResult& aRv) const;
797 
798   /**
799    * GetNextSelectedTableCellElement() is a stateful method to retrieve
800    * selected table cell elements which are selected by 2nd or later ranges
801    * of Selection.  When you call GetFirstSelectedTableCellElement(), it
802    * resets internal counter of this method.  Then, following calls of
803    * GetNextSelectedTableCellElement() scans the remaining ranges of Selection.
804    * If a range selects a <td> or <th> element, returns the cell element.
805    * If a range selects an element but neither <td> nor <th> element, this
806    * ignores the range.  If a range is in a text node, returns null without
807    * throwing exception, but stops scanning the remaining ranges even you
808    * call this again.
809    * Note that this may cross <table> boundaries since this method just
810    * scans all ranges of Selection.  Therefore, returning cells which
811    * belong to different <table> elements.
812    *
813    * @param aRv                 Returns error if Selection doesn't have
814    *                            range properly.
815    * @return                    A <td> or <th> element if one of remaining
816    *                            ranges selects a <td> or <th> element unless
817    *                            this does not meet a range in a text node.
818    */
819   already_AddRefed<Element> GetNextSelectedTableCellElement(
820       ErrorResult& aRv) const;
821 
822   /**
823    * DeleteTableCellContentsWithTransaction() removes any contents in cell
824    * elements.  If two or more cell elements are selected, this removes
825    * all selected cells' contents.  Otherwise, this removes contents of
826    * a cell which contains first selection range.  This does not return
827    * error even if selection is not in cell element, just does nothing.
828    */
829   MOZ_CAN_RUN_SCRIPT nsresult DeleteTableCellContentsWithTransaction();
830 
831   static void IsNextCharInNodeWhitespace(nsIContent* aContent, int32_t aOffset,
832                                          bool* outIsSpace, bool* outIsNBSP,
833                                          nsIContent** outNode = nullptr,
834                                          int32_t* outOffset = 0);
835   static void IsPrevCharInNodeWhitespace(nsIContent* aContent, int32_t aOffset,
836                                          bool* outIsSpace, bool* outIsNBSP,
837                                          nsIContent** outNode = nullptr,
838                                          int32_t* outOffset = 0);
839 
840   /**
841    * extracts an element from the normal flow of the document and
842    * positions it, and puts it back in the normal flow.
843    * @param aElement [IN] the element
844    * @param aEnabled [IN] true to absolutely position the element,
845    *                      false to put it back in the normal flow
846    */
847   MOZ_CAN_RUN_SCRIPT nsresult SetPositionToAbsoluteOrStatic(Element& aElement,
848                                                             bool aEnabled);
849 
850   /**
851    * adds aChange to the z-index of an arbitrary element.
852    * @param aElement [IN] the element
853    * @param aChange  [IN] relative change to apply to current z-index of
854    *                      the element
855    * @param aReturn  [OUT] the new z-index of the element
856    */
857   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RelativeChangeElementZIndex(
858       Element& aElement, int32_t aChange, int32_t* aReturn);
859 
860   /**
861    * Join together any adjacent editable text nodes in the range.
862    */
863   MOZ_CAN_RUN_SCRIPT nsresult CollapseAdjacentTextNodes(nsRange& aRange);
864 
865   /**
866    * IsInVisibleTextFrames() returns true if all text in aText is in visible
867    * text frames.  Callers have to guarantee that there is no pending reflow.
868    */
869   bool IsInVisibleTextFrames(dom::Text& aText) const;
870 
871   /**
872    * IsVisibleTextNode() returns true if aText has visible text.  If it has
873    * only whitespaces and they are collapsed, returns false.
874    */
875   bool IsVisibleTextNode(Text& aText) const;
876 
877   /**
878    * IsEmptyNode() figures out if aNode is an empty node.  A block can have
879    * children and still be considered empty, if the children are empty or
880    * non-editable.
881    */
882   bool IsEmptyNode(nsINode& aNode, bool aSingleBRDoesntCount = false,
883                    bool aListOrCellNotEmpty = false,
884                    bool aSafeToAskFrames = false) const {
885     bool seenBR = false;
886     return IsEmptyNodeImpl(aNode, aSingleBRDoesntCount, aListOrCellNotEmpty,
887                            aSafeToAskFrames, &seenBR);
888   }
889 
890   bool IsEmptyNodeImpl(nsINode& aNode, bool aSingleBRDoesntCount,
891                        bool aListOrCellNotEmpty, bool aSafeToAskFrames,
892                        bool* aSeenBR) const;
893 
HasAttributes(Element * aElement)894   static bool HasAttributes(Element* aElement) {
895     MOZ_ASSERT(aElement);
896     uint32_t attrCount = aElement->GetAttrCount();
897     return attrCount > 1 ||
898            (1 == attrCount &&
899             !aElement->GetAttrNameAt(0)->Equals(nsGkAtoms::mozdirty));
900   }
901 
902   /**
903    * Content-based query returns true if <aProperty aAttribute=aValue> effects
904    * aNode.  If <aProperty aAttribute=aValue> contains aNode, but
905    * <aProperty aAttribute=SomeOtherValue> also contains aNode and the second is
906    * more deeply nested than the first, then the first does not effect aNode.
907    *
908    * @param aNode      The target of the query
909    * @param aProperty  The property that we are querying for
910    * @param aAttribute The attribute of aProperty, example: color in
911    *                   <FONT color="blue"> May be null.
912    * @param aValue     The value of aAttribute, example: blue in
913    *                   <FONT color="blue"> May be null.  Ignored if aAttribute
914    *                   is null.
915    * @param outValue   [OUT] the value of the attribute, if aIsSet is true
916    * @return           true if <aProperty aAttribute=aValue> effects
917    *                   aNode.
918    *
919    * The nsIContent variant returns aIsSet instead of using an out parameter.
920    */
921   static bool IsTextPropertySetByContent(nsINode* aNode, nsAtom* aProperty,
922                                          nsAtom* aAttribute,
923                                          const nsAString* aValue,
924                                          nsAString* outValue = nullptr);
925 
926   static dom::Element* GetLinkElement(nsINode* aNode);
927 
928   /**
929    * Small utility routine to test if a break node is visible to user.
930    */
931   bool IsVisibleBRElement(const nsINode* aNode);
932 
933   /**
934    * Helper routines for font size changing.
935    */
936   enum class FontSize { incr, decr };
937   MOZ_CAN_RUN_SCRIPT nsresult RelativeFontChangeOnTextNode(FontSize aDir,
938                                                            Text& aTextNode,
939                                                            int32_t aStartOffset,
940                                                            int32_t aEndOffset);
941 
942   MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertyOnNode(nsIContent& aNode,
943                                                       nsAtom& aProperty,
944                                                       nsAtom* aAttribute,
945                                                       const nsAString& aValue);
946 
947   /**
948    * SplitAncestorStyledInlineElementsAtRangeEdges() splits all ancestor inline
949    * elements in the block at both aStartPoint and aEndPoint if given style
950    * matches with some of them.
951    *
952    * @param aStartPoint Start of range to split ancestor inline elements.
953    * @param aEndPoint   End of range to split ancestor inline elements.
954    * @param aProperty   The style tag name which you want to split.  Set
955    *                    nullptr if you want to split any styled elements.
956    * @param aAttribute  Attribute name if aProperty has some styles like
957    *                    nsGkAtoms::font.
958    */
959   [[nodiscard]] MOZ_CAN_RUN_SCRIPT SplitRangeOffResult
960   SplitAncestorStyledInlineElementsAtRangeEdges(
961       const EditorDOMPoint& aStartPoint, const EditorDOMPoint& aEndPoint,
962       nsAtom* aProperty, nsAtom* aAttribute);
963 
964   /**
965    * SplitAncestorStyledInlineElementsAt() splits ancestor inline elements at
966    * aPointToSplit if specified style matches with them.
967    *
968    * @param aPointToSplit       The point to split style at.
969    * @param aProperty           The style tag name which you want to split.
970    *                            Set nullptr if you want to split any styled
971    *                            elements.
972    * @param aAttribute          Attribute name if aProperty has some styles
973    *                            like nsGkAtoms::font.
974    * @return                    The result of SplitNodeDeepWithTransaction()
975    *                            with topmost split element.  If this didn't
976    *                            find inline elements to be split, Handled()
977    *                            returns false.
978    */
979   [[nodiscard]] MOZ_CAN_RUN_SCRIPT SplitNodeResult
980   SplitAncestorStyledInlineElementsAt(const EditorDOMPoint& aPointToSplit,
981                                       nsAtom* aProperty, nsAtom* aAttribute);
982 
983   /**
984    * GetPriorHTMLSibling() returns the previous editable sibling, if there is
985    * one within the parent, optionally skipping text nodes that are only
986    * whitespace.
987    */
988   enum class SkipWhitespace { Yes, No };
989   nsIContent* GetPriorHTMLSibling(nsINode* aNode,
990                                   SkipWhitespace = SkipWhitespace::No) const;
991 
992   /**
993    * GetNextHTMLSibling() returns the next editable sibling, if there is
994    * one within the parent, optionally skipping text nodes that are only
995    * whitespace.
996    */
997   nsIContent* GetNextHTMLSibling(nsINode* aNode,
998                                  SkipWhitespace = SkipWhitespace::No) const;
999 
1000   // Helper for GetPriorHTMLSibling/GetNextHTMLSibling.
SkippableWhitespace(nsINode * aNode,SkipWhitespace aSkipWS)1001   static bool SkippableWhitespace(nsINode* aNode, SkipWhitespace aSkipWS) {
1002     return aSkipWS == SkipWhitespace::Yes && aNode->IsText() &&
1003            aNode->AsText()->TextIsOnlyWhitespace();
1004   }
1005 
1006   /**
1007    * GetPreviousHTMLElementOrText*() methods are similar to
1008    * EditorBase::GetPreviousElementOrText*() but this won't return nodes
1009    * outside active editing host.
1010    */
GetPreviousHTMLElementOrText(const nsINode & aNode)1011   nsIContent* GetPreviousHTMLElementOrText(const nsINode& aNode) const {
1012     return GetPreviousHTMLElementOrTextInternal(aNode, false);
1013   }
GetPreviousHTMLElementOrTextInBlock(const nsINode & aNode)1014   nsIContent* GetPreviousHTMLElementOrTextInBlock(const nsINode& aNode) const {
1015     return GetPreviousHTMLElementOrTextInternal(aNode, true);
1016   }
1017   template <typename PT, typename CT>
GetPreviousHTMLElementOrText(const EditorDOMPointBase<PT,CT> & aPoint)1018   nsIContent* GetPreviousHTMLElementOrText(
1019       const EditorDOMPointBase<PT, CT>& aPoint) const {
1020     return GetPreviousHTMLElementOrTextInternal(aPoint, false);
1021   }
1022   template <typename PT, typename CT>
GetPreviousHTMLElementOrTextInBlock(const EditorDOMPointBase<PT,CT> & aPoint)1023   nsIContent* GetPreviousHTMLElementOrTextInBlock(
1024       const EditorDOMPointBase<PT, CT>& aPoint) const {
1025     return GetPreviousHTMLElementOrTextInternal(aPoint, true);
1026   }
1027 
1028   /**
1029    * GetPreviousHTMLElementOrTextInternal() methods are common implementation
1030    * of above methods.  Please don't use this method directly.
1031    */
1032   nsIContent* GetPreviousHTMLElementOrTextInternal(const nsINode& aNode,
1033                                                    bool aNoBlockCrossing) const;
1034   template <typename PT, typename CT>
1035   nsIContent* GetPreviousHTMLElementOrTextInternal(
1036       const EditorDOMPointBase<PT, CT>& aPoint, bool aNoBlockCrossing) const;
1037 
1038   /**
1039    * GetPreviousEditableHTMLNode*() methods are similar to
1040    * EditorBase::GetPreviousEditableNode() but this won't return nodes outside
1041    * active editing host.
1042    */
GetPreviousEditableHTMLNode(nsINode & aNode)1043   nsIContent* GetPreviousEditableHTMLNode(nsINode& aNode) const {
1044     return GetPreviousEditableHTMLNodeInternal(aNode, false);
1045   }
GetPreviousEditableHTMLNodeInBlock(nsINode & aNode)1046   nsIContent* GetPreviousEditableHTMLNodeInBlock(nsINode& aNode) const {
1047     return GetPreviousEditableHTMLNodeInternal(aNode, true);
1048   }
1049   template <typename PT, typename CT>
GetPreviousEditableHTMLNode(const EditorDOMPointBase<PT,CT> & aPoint)1050   nsIContent* GetPreviousEditableHTMLNode(
1051       const EditorDOMPointBase<PT, CT>& aPoint) const {
1052     return GetPreviousEditableHTMLNodeInternal(aPoint, false);
1053   }
1054   template <typename PT, typename CT>
GetPreviousEditableHTMLNodeInBlock(const EditorDOMPointBase<PT,CT> & aPoint)1055   nsIContent* GetPreviousEditableHTMLNodeInBlock(
1056       const EditorDOMPointBase<PT, CT>& aPoint) const {
1057     return GetPreviousEditableHTMLNodeInternal(aPoint, true);
1058   }
1059 
1060   /**
1061    * GetPreviousEditableHTMLNodeInternal() methods are common implementation
1062    * of above methods.  Please don't use this method directly.
1063    */
1064   nsIContent* GetPreviousEditableHTMLNodeInternal(nsINode& aNode,
1065                                                   bool aNoBlockCrossing) const;
1066   template <typename PT, typename CT>
1067   nsIContent* GetPreviousEditableHTMLNodeInternal(
1068       const EditorDOMPointBase<PT, CT>& aPoint, bool aNoBlockCrossing) const;
1069 
1070   /**
1071    * GetNextHTMLElementOrText*() methods are similar to
1072    * EditorBase::GetNextElementOrText*() but this won't return nodes outside
1073    * active editing host.
1074    *
1075    * Note that same as EditorBase::GetTextEditableNode(), methods which take
1076    * |const EditorRawDOMPoint&| start to search from the node pointed by it.
1077    * On the other hand, methods which take |nsINode&| start to search from
1078    * next node of aNode.
1079    */
GetNextHTMLElementOrText(const nsINode & aNode)1080   nsIContent* GetNextHTMLElementOrText(const nsINode& aNode) const {
1081     return GetNextHTMLElementOrTextInternal(aNode, false);
1082   }
GetNextHTMLElementOrTextInBlock(const nsINode & aNode)1083   nsIContent* GetNextHTMLElementOrTextInBlock(const nsINode& aNode) const {
1084     return GetNextHTMLElementOrTextInternal(aNode, true);
1085   }
1086   template <typename PT, typename CT>
GetNextHTMLElementOrText(const EditorDOMPointBase<PT,CT> & aPoint)1087   nsIContent* GetNextHTMLElementOrText(
1088       const EditorDOMPointBase<PT, CT>& aPoint) const {
1089     return GetNextHTMLElementOrTextInternal(aPoint, false);
1090   }
1091   template <typename PT, typename CT>
GetNextHTMLElementOrTextInBlock(const EditorDOMPointBase<PT,CT> & aPoint)1092   nsIContent* GetNextHTMLElementOrTextInBlock(
1093       const EditorDOMPointBase<PT, CT>& aPoint) const {
1094     return GetNextHTMLElementOrTextInternal(aPoint, true);
1095   }
1096 
1097   /**
1098    * GetNextHTMLNodeInternal() methods are common implementation
1099    * of above methods.  Please don't use this method directly.
1100    */
1101   nsIContent* GetNextHTMLElementOrTextInternal(const nsINode& aNode,
1102                                                bool aNoBlockCrossing) const;
1103   template <typename PT, typename CT>
1104   nsIContent* GetNextHTMLElementOrTextInternal(
1105       const EditorDOMPointBase<PT, CT>& aPoint, bool aNoBlockCrossing) const;
1106 
1107   /**
1108    * GetNextEditableHTMLNode*() methods are similar to
1109    * EditorBase::GetNextEditableNode() but this won't return nodes outside
1110    * active editing host.
1111    *
1112    * Note that same as EditorBase::GetTextEditableNode(), methods which take
1113    * |const EditorRawDOMPoint&| start to search from the node pointed by it.
1114    * On the other hand, methods which take |nsINode&| start to search from
1115    * next node of aNode.
1116    */
GetNextEditableHTMLNode(nsINode & aNode)1117   nsIContent* GetNextEditableHTMLNode(nsINode& aNode) const {
1118     return GetNextEditableHTMLNodeInternal(aNode, false);
1119   }
GetNextEditableHTMLNodeInBlock(nsINode & aNode)1120   nsIContent* GetNextEditableHTMLNodeInBlock(nsINode& aNode) const {
1121     return GetNextEditableHTMLNodeInternal(aNode, true);
1122   }
1123   template <typename PT, typename CT>
GetNextEditableHTMLNode(const EditorDOMPointBase<PT,CT> & aPoint)1124   nsIContent* GetNextEditableHTMLNode(
1125       const EditorDOMPointBase<PT, CT>& aPoint) const {
1126     return GetNextEditableHTMLNodeInternal(aPoint, false);
1127   }
1128   template <typename PT, typename CT>
GetNextEditableHTMLNodeInBlock(const EditorDOMPointBase<PT,CT> & aPoint)1129   nsIContent* GetNextEditableHTMLNodeInBlock(
1130       const EditorDOMPointBase<PT, CT>& aPoint) const {
1131     return GetNextEditableHTMLNodeInternal(aPoint, true);
1132   }
1133 
1134   /**
1135    * GetNextEditableHTMLNodeInternal() methods are common implementation
1136    * of above methods.  Please don't use this method directly.
1137    */
1138   nsIContent* GetNextEditableHTMLNodeInternal(nsINode& aNode,
1139                                               bool aNoBlockCrossing) const;
1140   template <typename PT, typename CT>
1141   nsIContent* GetNextEditableHTMLNodeInternal(
1142       const EditorDOMPointBase<PT, CT>& aPoint, bool aNoBlockCrossing) const;
1143 
1144   bool IsFirstEditableChild(nsINode* aNode) const;
1145   bool IsLastEditableChild(nsINode* aNode) const;
1146   nsIContent* GetFirstEditableChild(nsINode& aNode) const;
1147   nsIContent* GetLastEditableChild(nsINode& aNode) const;
1148 
1149   nsIContent* GetFirstEditableLeaf(nsINode& aNode) const;
1150   nsIContent* GetLastEditableLeaf(nsINode& aNode) const;
1151 
1152   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlinePropertyBase(
1153       nsAtom& aHTMLProperty, nsAtom* aAttribute, const nsAString* aValue,
1154       bool* aFirst, bool* aAny, bool* aAll, nsAString* outValue) const;
1155 
1156   /**
1157    * ClearStyleAt() splits parent elements to remove the specified style.
1158    * If this splits some parent elements at near their start or end, such
1159    * empty elements will be removed.  Then, remove the specified style
1160    * from the point and returns DOM point to put caret.
1161    *
1162    * @param aPoint      The point to clear style at.
1163    * @param aProperty   An HTML tag name which represents a style.
1164    *                    Set nullptr if you want to clear all styles.
1165    * @param aAttribute  Attribute name if aProperty has some styles like
1166    *                    nsGkAtoms::font.
1167    */
1168   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditResult ClearStyleAt(
1169       const EditorDOMPoint& aPoint, nsAtom* aProperty, nsAtom* aAttribute);
1170 
1171   MOZ_CAN_RUN_SCRIPT nsresult SetPositionToAbsolute(Element& aElement);
1172   MOZ_CAN_RUN_SCRIPT nsresult SetPositionToStatic(Element& aElement);
1173 
1174   /**
1175    * OnModifyDocument() is called when the editor is changed.  This should
1176    * be called only by runnable in HTMLEditor::OnDocumentModified() to call
1177    * HTMLEditor::OnModifyDocument() with AutoEditActionDataSetter instance.
1178    */
1179   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult OnModifyDocument();
1180 
1181   /**
1182    * DoSplitNode() creates a new node (left node) identical to an existing
1183    * node (right node), and split the contents between the same point in both
1184    * nodes.
1185    *
1186    * @param aStartOfRightNode   The point to split.  Its container will be
1187    *                            the right node, i.e., become the new node's
1188    *                            next sibling.  And the point will be start
1189    *                            of the right node.
1190    * @param aNewLeftNode        The new node called as left node, so, this
1191    *                            becomes the container of aPointToSplit's
1192    *                            previous sibling.
1193    * @param aError              Must have not already failed.
1194    *                            If succeed to insert aLeftNode before the
1195    *                            right node and remove unnecessary contents
1196    *                            (and collapse selection at end of the left
1197    *                            node if necessary), returns no error.
1198    *                            Otherwise, an error.
1199    */
1200   MOZ_CAN_RUN_SCRIPT void DoSplitNode(const EditorDOMPoint& aStartOfRightNode,
1201                                       nsIContent& aNewLeftNode,
1202                                       ErrorResult& aError);
1203 
1204   /**
1205    * DoJoinNodes() merges contents in aContentToJoin to aContentToKeep and
1206    * remove aContentToJoin from the DOM tree.  aContentToJoin and aContentToKeep
1207    * must have same parent, aParent.  Additionally, if one of aContentToJoin or
1208    * aContentToKeep is a text node, the other must be a text node.
1209    *
1210    * @param aContentToKeep  The node that will remain after the join.
1211    * @param aContentToJoin  The node that will be joined with aContentToKeep.
1212    *                        There is no requirement that the two nodes be of the
1213    *                        same type.
1214    */
1215   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1216   DoJoinNodes(nsIContent& aContentToKeep, nsIContent& aContentToJoin);
1217 
1218  protected:  // edit sub-action handler
1219   /**
1220    * CanHandleHTMLEditSubAction() checks whether there is at least one
1221    * selection range or not, and whether the first range is editable.
1222    * If it's not editable, `Canceled()` of the result returns true.
1223    * If `Selection` is in odd situation, returns an error.
1224    *
1225    * XXX I think that `IsSelectionEditable()` is better name, but it's already
1226    *     in `EditorBase`...
1227    */
1228   EditActionResult CanHandleHTMLEditSubAction() const;
1229 
1230   /**
1231    * EnsureCaretNotAfterPaddingBRElement() makes sure that caret is NOT after
1232    * padding `<br>` element for preventing insertion after padding `<br>`
1233    * element at empty last line.
1234    * NOTE: This method should be called only when `Selection` is collapsed
1235    *       because `Selection` is a pain to work with when not collapsed.
1236    *       (no good way to extend start or end of selection), so we need to
1237    *       ignore those types of selections.
1238    */
1239   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1240   EnsureCaretNotAfterPaddingBRElement();
1241 
1242   /**
1243    * PrepareInlineStylesForCaret() consider inline styles from top level edit
1244    * sub-action and setting it to `mTypeInState` and clear inline style cache
1245    * if necessary.
1246    * NOTE: This method should be called only when `Selection` is collapsed.
1247    */
1248   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult PrepareInlineStylesForCaret();
1249 
1250   /**
1251    * HandleInsertText() handles inserting text at selection.
1252    *
1253    * @param aEditSubAction      Must be EditSubAction::eInsertText or
1254    *                            EditSubAction::eInsertTextComingFromIME.
1255    * @param aInsertionString    String to be inserted at selection.
1256    */
1257   [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual EditActionResult HandleInsertText(
1258       EditSubAction aEditSubAction, const nsAString& aInsertionString) final;
1259 
1260   /**
1261    * GetInlineStyles() retrieves the style of aNode and modifies each item of
1262    * aStyleCacheArray.  This might cause flushing layout at retrieving computed
1263    * values of CSS properties.
1264    */
1265   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1266   GetInlineStyles(nsIContent& aContent, AutoStyleCacheArray& aStyleCacheArray);
1267 
1268   /**
1269    * CacheInlineStyles() caches style of aContent into mCachedInlineStyles of
1270    * TopLevelEditSubAction.  This may cause flushing layout at retrieving
1271    * computed value of CSS properties.
1272    */
1273   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1274   CacheInlineStyles(nsIContent& aContent);
1275 
1276   /**
1277    * ReapplyCachedStyles() restores some styles which are disappeared during
1278    * handling edit action and it should be restored.  This may cause flushing
1279    * layout at retrieving computed value of CSS properties.
1280    */
1281   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ReapplyCachedStyles();
1282 
1283   /**
1284    * CreateStyleForInsertText() sets CSS properties which are stored in
1285    * TypeInState to proper element node.
1286    * XXX This modifies Selection, but should return insertion point instead.
1287    *
1288    * @param aAbstractRange      Set current selection range where new text
1289    *                            should be inserted.
1290    */
1291   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1292   CreateStyleForInsertText(const dom::AbstractRange& aAbstractRange);
1293 
1294   /**
1295    * GetMostAncestorMailCiteElement() returns most-ancestor mail cite element.
1296    * "mail cite element" is <pre> element when it's in plaintext editor mode
1297    * or an element with which calling HTMLEditUtils::IsMailCite() returns true.
1298    *
1299    * @param aNode       The start node to look for parent mail cite elements.
1300    */
1301   Element* GetMostAncestorMailCiteElement(nsINode& aNode) const;
1302 
1303   /**
1304    * SplitMailCiteElements() splits mail-cite elements at start of Selection if
1305    * Selection starts from inside a mail-cite element.  Of course, if it's
1306    * necessary, this inserts <br> node to new left nodes or existing right
1307    * nodes.
1308    * XXX This modifies Selection, but should return SplitNodeResult() instead.
1309    */
1310   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
1311   SplitMailCiteElements(const EditorDOMPoint& aPointToSplit);
1312 
1313   /**
1314    * InsertBRElement() inserts a <br> element into aInsertToBreak.
1315    * This may split container elements at the point and/or may move following
1316    * <br> element to immediately after the new <br> element if necessary.
1317    * XXX This method name is too generic and unclear whether such complicated
1318    *     things will be done automatically or not.
1319    * XXX This modifies Selection, but should return CreateElementResult instead.
1320    *
1321    * @param aInsertToBreak      The point where new <br> element will be
1322    *                            inserted before.
1323    */
1324   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1325   InsertBRElement(const EditorDOMPoint& aInsertToBreak);
1326 
1327   /**
1328    * GetMostAncestorInlineElement() returns the most ancestor inline element
1329    * between aNode and the editing host.  Even if the editing host is an inline
1330    * element, this method never returns the editing host as the result.
1331    */
1332   nsIContent* GetMostAncestorInlineElement(nsINode& aNode) const;
1333 
1334   /**
1335    * SplitParentInlineElementsAtRangeEdges() splits parent inline nodes at both
1336    * start and end of aRangeItem.  If this splits at every point, this modifies
1337    * aRangeItem to point each split point (typically, right node).
1338    *
1339    * @param aRangeItem          [in/out] One or two DOM points where should be
1340    *                            split.  Will be modified to split point if
1341    *                            they're split.
1342    */
1343   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1344   SplitParentInlineElementsAtRangeEdges(RangeItem& aRangeItem);
1345 
1346   /**
1347    * SplitParentInlineElementsAtRangeEdges(nsTArray<RefPtr<nsRange>>&) calls
1348    * SplitParentInlineElementsAtRangeEdges(RangeItem&) for each range.  Then,
1349    * updates given range to keep edit target ranges as expected.
1350    */
1351   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1352   SplitParentInlineElementsAtRangeEdges(
1353       nsTArray<RefPtr<nsRange>>& aArrayOfRanges);
1354 
1355   /**
1356    * SplitElementsAtEveryBRElement() splits before all <br> elements in
1357    * aMostAncestorToBeSplit.  All <br> nodes will be moved before right node
1358    * at splitting its parent.  Finally, this returns left node, first <br>
1359    * element, next left node, second <br> element... and right-most node.
1360    *
1361    * @param aMostAncestorToBeSplit      Most-ancestor element which should
1362    *                                    be split.
1363    * @param aOutArrayOfNodes            First left node, first <br> element,
1364    *                                    Second left node, second <br> element,
1365    *                                    ...right-most node.  So, all nodes
1366    *                                    in this list should be siblings (may be
1367    *                                    broken the relation by mutation event
1368    *                                    listener though). If first <br> element
1369    *                                    is first leaf node of
1370    *                                    aMostAncestorToBeSplit, starting from
1371    *                                    the first <br> element.
1372    */
1373   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SplitElementsAtEveryBRElement(
1374       nsIContent& aMostAncestorToBeSplit,
1375       nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents);
1376 
1377   /**
1378    * MaybeSplitElementsAtEveryBRElement() calls SplitElementsAtEveryBRElement()
1379    * for each given node when this needs to do that for aEditSubAction.
1380    * If split a node, it in aArrayOfContents is replaced with split nodes and
1381    * <br> elements.
1382    */
1383   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MaybeSplitElementsAtEveryBRElement(
1384       nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
1385       EditSubAction aEditSubAction);
1386 
1387   /**
1388    * CollectEditableChildren() collects child nodes of aNode (starting from
1389    * first editable child, but may return non-editable children after it).
1390    *
1391    * @param aNode               Parent node of retrieving children.
1392    * @param aOutArrayOfContents [out] This method will inserts found children
1393    *                            into this array.
1394    * @param aIndexToInsertChildren      Starting from this index, found
1395    *                                    children will be inserted to the array.
1396    * @param aCollectListChildren        If Yes, will collect children of list
1397    *                                    and list-item elements recursively.
1398    * @param aCollectTableChildren       If Yes, will collect children of table
1399    *                                    related elements recursively.
1400    * @param aCollectNonEditableNodes    If Yes, will collect found children
1401    *                                    even if they are not editable.
1402    * @return                    Number of found children.
1403    */
1404   enum class CollectListChildren { No, Yes };
1405   enum class CollectTableChildren { No, Yes };
1406   enum class CollectNonEditableNodes { No, Yes };
1407   size_t CollectChildren(
1408       nsINode& aNode, nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents,
1409       size_t aIndexToInsertChildren, CollectListChildren aCollectListChildren,
1410       CollectTableChildren aCollectTableChildren,
1411       CollectNonEditableNodes aCollectNonEditableNodes) const;
1412 
1413   /**
1414    * SplitInlinessAndCollectEditTargetNodes() splits text nodes and inline
1415    * elements around aArrayOfRanges.  Then, collects edit target nodes to
1416    * aOutArrayOfNodes.  Finally, each edit target nodes is split at every
1417    * <br> element in it.
1418    * FYI: You can use SplitInlinesAndCollectEditTargetNodesInOneHardLine()
1419    *      or SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges()
1420    *      instead if you want to call this with a hard line including
1421    *      specific DOM point or extended selection ranges.
1422    */
1423   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1424   SplitInlinesAndCollectEditTargetNodes(
1425       nsTArray<RefPtr<nsRange>>& aArrayOfRanges,
1426       nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents,
1427       EditSubAction aEditSubAction,
1428       CollectNonEditableNodes aCollectNonEditableNodes);
1429 
1430   /**
1431    * SplitTextNodesAtRangeEnd() splits text nodes if each range end is in
1432    * middle of a text node.
1433    */
1434   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1435   SplitTextNodesAtRangeEnd(nsTArray<RefPtr<nsRange>>& aArrayOfRanges);
1436 
1437   /**
1438    * CollectEditTargetNodes() collects edit target nodes in aArrayOfRanges.
1439    * First, this collects all nodes in given ranges, then, modifies the
1440    * result for specific edit sub-actions.
1441    * FYI: You can use CollectEditTargetNodesInExtendedSelectionRanges() instead
1442    *      if you want to call this with extended selection ranges.
1443    */
1444   nsresult CollectEditTargetNodes(
1445       nsTArray<RefPtr<nsRange>>& aArrayOfRanges,
1446       nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents,
1447       EditSubAction aEditSubAction,
1448       CollectNonEditableNodes aCollectNonEditableNodes);
1449 
1450   /**
1451    * GetWhiteSpaceEndPoint() returns point at first or last ASCII whitespace
1452    * or non-breakable space starting from aPoint.  I.e., this returns next or
1453    * previous point whether the character is neither ASCII whitespace nor
1454    * non-brekable space.
1455    */
1456   enum class ScanDirection { Backward, Forward };
1457   template <typename PT, typename RT>
1458   static EditorDOMPoint GetWhiteSpaceEndPoint(
1459       const RangeBoundaryBase<PT, RT>& aPoint, ScanDirection aScanDirection);
1460 
1461   /**
1462    * GetCurrentHardLineStartPoint() returns start point of hard line
1463    * including aPoint.  If the line starts after a `<br>` element, returns
1464    * next sibling of the `<br>` element.  If the line is first line of a block,
1465    * returns point of the block.
1466    * NOTE: The result may be point of editing host.  I.e., the container may
1467    *       be outside of editing host.
1468    */
1469   template <typename PT, typename RT>
1470   EditorDOMPoint GetCurrentHardLineStartPoint(
1471       const RangeBoundaryBase<PT, RT>& aPoint, EditSubAction aEditSubAction);
1472 
1473   /**
1474    * GetCurrentHardLineEndPoint() returns end point of hard line including
1475    * aPoint.  If the line ends with a `<br>` element, returns the `<br>`
1476    * element unless it's the last node of a block.  If the line is last line
1477    * of a block, returns next sibling of the block.  Additionally, if the
1478    * line ends with a linefeed in pre-formated text node, returns point of
1479    * the linefeed.
1480    * NOTE: This result may be point of editing host.  I.e., the container
1481    *       may be outside of editing host.
1482    */
1483   template <typename PT, typename RT>
1484   EditorDOMPoint GetCurrentHardLineEndPoint(
1485       const RangeBoundaryBase<PT, RT>& aPoint);
1486 
1487   /**
1488    * CreateRangeIncludingAdjuscentWhiteSpaces() creates an nsRange instance
1489    * which may be expanded from the given range to include adjuscent
1490    * whitespaces.  If this fails handling something, returns nullptr.
1491    */
1492   already_AddRefed<nsRange> CreateRangeIncludingAdjuscentWhiteSpaces(
1493       const dom::AbstractRange& aAbstractRange);
1494   template <typename SPT, typename SRT, typename EPT, typename ERT>
1495   already_AddRefed<nsRange> CreateRangeIncludingAdjuscentWhiteSpaces(
1496       const RangeBoundaryBase<SPT, SRT>& aStartRef,
1497       const RangeBoundaryBase<EPT, ERT>& aEndRef);
1498 
1499   /**
1500    * GetSelectionRangesExtendedToIncludeAdjuscentWhiteSpaces() collects
1501    * selection ranges with extending to include adjuscent whitespaces
1502    * of each range start and end.
1503    *
1504    * @param aOutArrayOfRanges   [out] Always appended same number of ranges
1505    *                            as Selection::RangeCount().  Must be empty
1506    *                            when you call this.
1507    */
1508   void GetSelectionRangesExtendedToIncludeAdjuscentWhiteSpaces(
1509       nsTArray<RefPtr<nsRange>>& aOutArrayOfRanges);
1510 
1511   /**
1512    * CreateRangeExtendedToHardLineStartAndEnd() creates an nsRange instance
1513    * which may be expanded to start/end of hard line at both edges of the given
1514    * range.  If this fails handling something, returns nullptr.
1515    */
1516   already_AddRefed<nsRange> CreateRangeExtendedToHardLineStartAndEnd(
1517       const dom::AbstractRange& aAbstractRange, EditSubAction aEditSubAction);
1518   template <typename SPT, typename SRT, typename EPT, typename ERT>
1519   already_AddRefed<nsRange> CreateRangeExtendedToHardLineStartAndEnd(
1520       const RangeBoundaryBase<SPT, SRT>& aStartRef,
1521       const RangeBoundaryBase<EPT, ERT>& aEndRef, EditSubAction aEditSubAction);
1522 
1523   /**
1524    * GetSelectionRangesExtendedToHardLineStartAndEnd() collects selection ranges
1525    * with extending to start/end of hard line from each range start and end.
1526    * XXX This means that same range may be included in the result.
1527    *
1528    * @param aOutArrayOfRanges   [out] Always appended same number of ranges
1529    *                            as Selection::RangeCount().  Must be empty
1530    *                            when you call this.
1531    */
1532   void GetSelectionRangesExtendedToHardLineStartAndEnd(
1533       nsTArray<RefPtr<nsRange>>& aOutArrayOfRanges,
1534       EditSubAction aEditSubAction);
1535 
1536   /**
1537    * SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges() calls
1538    * SplitInlinesAndCollectEditTargetNodes() with result of
1539    * GetSelectionRangesExtendedToHardLineStartAndEnd().  See comments for these
1540    * methods for the detail.
1541    */
1542   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(nsTArray<OwningNonNull<nsIContent>> & aOutArrayOfContents,EditSubAction aEditSubAction,CollectNonEditableNodes aCollectNonEditableNodes)1543   SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
1544       nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents,
1545       EditSubAction aEditSubAction,
1546       CollectNonEditableNodes aCollectNonEditableNodes) {
1547     AutoTArray<RefPtr<nsRange>, 4> extendedSelectionRanges;
1548     GetSelectionRangesExtendedToHardLineStartAndEnd(extendedSelectionRanges,
1549                                                     aEditSubAction);
1550     nsresult rv = SplitInlinesAndCollectEditTargetNodes(
1551         extendedSelectionRanges, aOutArrayOfContents, aEditSubAction,
1552         aCollectNonEditableNodes);
1553     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1554                          "SplitInlinesAndCollectEditTargetNodes() failed");
1555     return rv;
1556   }
1557 
1558   /**
1559    * SplitInlinesAndCollectEditTargetNodesInOneHardLine() just calls
1560    * SplitInlinesAndCollectEditTargetNodes() with result of calling
1561    * CreateRangeExtendedToHardLineStartAndEnd() with aPointInOneHardLine.
1562    * In other words, returns nodes in the hard line including
1563    * `aPointInOneHardLine`.  See the comments for these methods for the
1564    * detail.
1565    */
1566   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
SplitInlinesAndCollectEditTargetNodesInOneHardLine(const EditorDOMPoint & aPointInOneHardLine,nsTArray<OwningNonNull<nsIContent>> & aOutArrayOfContents,EditSubAction aEditSubAction,CollectNonEditableNodes aCollectNonEditableNodes)1567   SplitInlinesAndCollectEditTargetNodesInOneHardLine(
1568       const EditorDOMPoint& aPointInOneHardLine,
1569       nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents,
1570       EditSubAction aEditSubAction,
1571       CollectNonEditableNodes aCollectNonEditableNodes) {
1572     if (NS_WARN_IF(!aPointInOneHardLine.IsSet())) {
1573       return NS_ERROR_INVALID_ARG;
1574     }
1575     RefPtr<nsRange> oneLineRange = CreateRangeExtendedToHardLineStartAndEnd(
1576         aPointInOneHardLine.ToRawRangeBoundary(),
1577         aPointInOneHardLine.ToRawRangeBoundary(), aEditSubAction);
1578     if (!oneLineRange) {
1579       // XXX It seems odd to create collapsed range for one line range...
1580       ErrorResult error;
1581       oneLineRange =
1582           nsRange::Create(aPointInOneHardLine.ToRawRangeBoundary(),
1583                           aPointInOneHardLine.ToRawRangeBoundary(), error);
1584       if (NS_WARN_IF(error.Failed())) {
1585         return error.StealNSResult();
1586       }
1587     }
1588     AutoTArray<RefPtr<nsRange>, 1> arrayOfLineRanges;
1589     arrayOfLineRanges.AppendElement(oneLineRange);
1590     nsresult rv = SplitInlinesAndCollectEditTargetNodes(
1591         arrayOfLineRanges, aOutArrayOfContents, aEditSubAction,
1592         aCollectNonEditableNodes);
1593     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1594                          "SplitInlinesAndCollectEditTargetNodes() failed");
1595     return rv;
1596   }
1597 
1598   /**
1599    * CollectEditTargetNodesInExtendedSelectionRanges() calls
1600    * CollectEditTargetNodes() with result of
1601    * GetSelectionRangesExtendedToHardLineStartAndEnd().  See comments for these
1602    * methods for the detail.
1603    */
CollectEditTargetNodesInExtendedSelectionRanges(nsTArray<OwningNonNull<nsIContent>> & aOutArrayOfContents,EditSubAction aEditSubAction,CollectNonEditableNodes aCollectNonEditableNodes)1604   nsresult CollectEditTargetNodesInExtendedSelectionRanges(
1605       nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents,
1606       EditSubAction aEditSubAction,
1607       CollectNonEditableNodes aCollectNonEditableNodes) {
1608     AutoTArray<RefPtr<nsRange>, 4> extendedSelectionRanges;
1609     GetSelectionRangesExtendedToHardLineStartAndEnd(extendedSelectionRanges,
1610                                                     aEditSubAction);
1611     nsresult rv =
1612         CollectEditTargetNodes(extendedSelectionRanges, aOutArrayOfContents,
1613                                aEditSubAction, aCollectNonEditableNodes);
1614     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "CollectEditTargetNodes() failed");
1615     return rv;
1616   }
1617 
1618   /**
1619    * SelectBRElementIfCollapsedInEmptyBlock() helper method for
1620    * CreateRangeIncludingAdjuscentWhiteSpaces() and
1621    * CreateRangeExtendedToLineStartAndEnd().  If the given range is collapsed
1622    * in a block and the block has only one `<br>` element, this makes
1623    * aStartRef and aEndRef select the `<br>` element.
1624    */
1625   template <typename SPT, typename SRT, typename EPT, typename ERT>
1626   void SelectBRElementIfCollapsedInEmptyBlock(
1627       RangeBoundaryBase<SPT, SRT>& aStartRef,
1628       RangeBoundaryBase<EPT, ERT>& aEndRef);
1629 
1630   /**
1631    * GetChildNodesOf() returns all child nodes of aParent with an array.
1632    */
GetChildNodesOf(nsINode & aParentNode,nsTArray<OwningNonNull<nsIContent>> & aOutArrayOfContents)1633   static void GetChildNodesOf(
1634       nsINode& aParentNode,
1635       nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents) {
1636     MOZ_ASSERT(aOutArrayOfContents.IsEmpty());
1637     aOutArrayOfContents.SetCapacity(aParentNode.GetChildCount());
1638     for (nsIContent* childContent = aParentNode.GetFirstChild(); childContent;
1639          childContent = childContent->GetNextSibling()) {
1640       aOutArrayOfContents.AppendElement(*childContent);
1641     }
1642   }
1643 
1644   /**
1645    * GetDeepestEditableOnlyChildDivBlockquoteOrListElement() returns a `<div>`,
1646    * `<blockquote>` or one of list elements.  This method climbs down from
1647    * aContent while there is only one editable children and the editable child
1648    * is `<div>`, `<blockquote>` or a list element.  When it reaches different
1649    * kind of node, returns the last found element.
1650    */
1651   Element* GetDeepestEditableOnlyChildDivBlockquoteOrListElement(
1652       nsINode& aNode);
1653 
1654   /**
1655    * Try to get parent list element at `Selection`.  This returns first find
1656    * parent list element of common ancestor of ranges (looking for it from
1657    * first range to last range).
1658    */
1659   Element* GetParentListElementAtSelection() const;
1660 
1661   /**
1662    * MaybeExtendSelectionToHardLineEdgesForBlockEditAction() adjust Selection if
1663    * there is only one range.  If range start and/or end point is <br> node or
1664    * something non-editable point, they should be moved to nearest text node or
1665    * something where the other methods easier to handle edit action.
1666    */
1667   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1668   MaybeExtendSelectionToHardLineEdgesForBlockEditAction();
1669 
1670   /**
1671    * IsEmptyInlineNode() returns true if aContent is an inline node and it does
1672    * not have meaningful content.
1673    */
1674   bool IsEmptyInlineNode(nsIContent& aContent) const;
1675 
1676   /**
1677    * IsEmptyOneHardLine() returns true if aArrayOfContents does not represent
1678    * 2 or more lines and have meaningful content.
1679    */
IsEmptyOneHardLine(nsTArray<OwningNonNull<nsIContent>> & aArrayOfContents)1680   bool IsEmptyOneHardLine(
1681       nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents) const {
1682     if (NS_WARN_IF(aArrayOfContents.IsEmpty())) {
1683       return true;
1684     }
1685 
1686     bool brElementHasFound = false;
1687     for (OwningNonNull<nsIContent>& content : aArrayOfContents) {
1688       if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
1689         continue;
1690       }
1691       if (content->IsHTMLElement(nsGkAtoms::br)) {
1692         // If there are 2 or more `<br>` elements, it's not empty line since
1693         // there may be only one `<br>` element in a hard line.
1694         if (brElementHasFound) {
1695           return false;
1696         }
1697         brElementHasFound = true;
1698         continue;
1699       }
1700       if (!IsEmptyInlineNode(content)) {
1701         return false;
1702       }
1703     }
1704     return true;
1705   }
1706 
1707   /**
1708    * MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of
1709    * aStartOfDeepestRightNode can have an element whose tag name is aTag.
1710    * Otherwise, looks for an ancestor node which is or is in active editing
1711    * host and can have an element whose name is aTag.  If there is such
1712    * ancestor, its descendants are split.
1713    *
1714    * Note that this may create empty elements while splitting ancestors.
1715    *
1716    * @param aTag                        The name of element to be inserted
1717    *                                    after calling this method.
1718    * @param aStartOfDeepestRightNode    The start point of deepest right node.
1719    *                                    This point must be descendant of
1720    *                                    active editing host.
1721    * @return                            When succeeded, SplitPoint() returns
1722    *                                    the point to insert the element.
1723    */
1724   [[nodiscard]] MOZ_CAN_RUN_SCRIPT SplitNodeResult
1725   MaybeSplitAncestorsForInsertWithTransaction(
1726       nsAtom& aTag, const EditorDOMPoint& aStartOfDeepestRightNode);
1727 
1728   /**
1729    * SplitRangeOffFromBlock() splits aBlockElement at two points, before
1730    * aStartOfMiddleElement and after aEndOfMiddleElement.  If they are very
1731    * start or very end of aBlcok, this won't create empty block.
1732    *
1733    * @param aBlockElement           A block element which will be split.
1734    * @param aStartOfMiddleElement   Start node of middle block element.
1735    * @param aEndOfMiddleElement     End node of middle block element.
1736    */
1737   [[nodiscard]] MOZ_CAN_RUN_SCRIPT SplitRangeOffFromNodeResult
1738   SplitRangeOffFromBlock(Element& aBlockElement,
1739                          nsIContent& aStartOfMiddleElement,
1740                          nsIContent& aEndOfMiddleElement);
1741 
1742   /**
1743    * SplitRangeOffFromBlockAndRemoveMiddleContainer() splits the nodes
1744    * between aStartOfRange and aEndOfRange, then, removes the middle element
1745    * and moves its content to where the middle element was.
1746    *
1747    * @param aBlockElement           The node which will be split.
1748    * @param aStartOfRange           The first node which will be unwrapped
1749    *                                from aBlockElement.
1750    * @param aEndOfRange             The last node which will be unwrapped from
1751    *                                aBlockElement.
1752    * @return                        The left content is new created left
1753    *                                element of aBlockElement.
1754    *                                The right content is split element,
1755    *                                i.e., must be aBlockElement.
1756    *                                The middle content is nullptr since
1757    *                                removing it is the job of this method.
1758    */
1759   [[nodiscard]] MOZ_CAN_RUN_SCRIPT SplitRangeOffFromNodeResult
1760   SplitRangeOffFromBlockAndRemoveMiddleContainer(Element& aBlockElement,
1761                                                  nsIContent& aStartOfRange,
1762                                                  nsIContent& aEndOfRange);
1763 
1764   /**
1765    * MoveNodesIntoNewBlockquoteElement() inserts at least one <blockquote>
1766    * element and moves nodes in aArrayOfContents into new <blockquote>
1767    * elements.
1768    * If aArrayOfContents includes a table related element except <table>,
1769    * this calls itself recursively to insert <blockquote> into the cell.
1770    *
1771    * @param aArrayOfContents    Nodes which will be moved into created
1772    *                            <blockquote> elements.
1773    */
1774   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MoveNodesIntoNewBlockquoteElement(
1775       nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents);
1776 
1777   /**
1778    * RemoveBlockContainerElements() removes all format blocks, table related
1779    * element, etc in aArrayOfContents from the DOM tree.
1780    * If aArrayOfContents has a format node, it will be removed and its contents
1781    * will be moved to where it was.
1782    * If aArrayOfContents has a table related element, <li>, <blockquote> or
1783    * <div>, it will be removed and its contents will be moved to where it was.
1784    */
1785   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveBlockContainerElements(
1786       nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents);
1787 
1788   /**
1789    * CreateOrChangeBlockContainerElement() formats all nodes in aArrayOfContents
1790    * with block elements whose name is aBlockTag.
1791    * If aArrayOfContents has an inline element, a block element is created and
1792    * the inline element and following inline elements are moved into the new
1793    * block element.
1794    * If aArrayOfContents has <br> elements, they'll be removed from the DOM
1795    * tree and new block element will be created when there are some remaining
1796    * inline elements.
1797    * If aArrayOfContents has a block element, this calls itself with children
1798    * of the block element.  Then, new block element will be created when there
1799    * are some remaining inline elements.
1800    *
1801    * @param aArrayOfContents    Must be descendants of a node.
1802    * @param aBlockTag           The element name of new block elements.
1803    */
1804   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult CreateOrChangeBlockContainerElement(
1805       nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents, nsAtom& aBlockTag);
1806 
1807   /**
1808    * FormatBlockContainerWithTransaction() is implementation of "formatBlock"
1809    * command of `Document.execCommand()`.  This applies block style or removes
1810    * it.
1811    * NOTE: This creates AutoSelectionRestorer.  Therefore, even when this
1812    *       return NS_OK, editor may have been destroyed.
1813    *
1814    * @param aBlockType          New block tag name.
1815    *                            If nsGkAtoms::normal or nsGkAtoms::_empty,
1816    *                            RemoveBlockContainerElements() will be called.
1817    *                            If nsGkAtoms::blockquote,
1818    *                            MoveNodesIntoNewBlockquoteElement() will be
1819    *                            called.  Otherwise,
1820    *                            CreateOrChangeBlockContainerElement() will be
1821    *                            called.
1822    */
1823   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1824   FormatBlockContainerWithTransaction(nsAtom& aBlockType);
1825 
1826   /**
1827    * InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary() determines if
1828    * aPointToInsert is start of a hard line and end of the line (i.e, the
1829    * line is empty) and the line ends with block boundary, inserts a `<br>`
1830    * element.
1831    */
1832   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1833   InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
1834       const EditorDOMPoint& aPointToInsert);
1835 
1836   /**
1837    * Insert a `<br>` element if aElement is a block element and empty.
1838    */
1839   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1840   InsertBRElementIfEmptyBlockElement(Element& aElement);
1841 
1842   /**
1843    * Insert padding `<br>` element for empty last line into aElement if
1844    * aElement is a block element and empty.
1845    */
1846   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1847   InsertPaddingBRElementForEmptyLastLineIfNeeded(Element& aElement);
1848 
1849   /**
1850    * This method inserts a padding `<br>` element for empty last line if
1851    * selection is collapsed and container of the range needs it.
1852    */
1853   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1854   MaybeInsertPaddingBRElementForEmptyLastLineAtSelection();
1855 
1856   /**
1857    * IsEmptyBlockElement() returns true if aElement is a block level element
1858    * and it doesn't have any visible content.
1859    */
1860   enum class IgnoreSingleBR { Yes, No };
1861   bool IsEmptyBlockElement(Element& aElement,
1862                            IgnoreSingleBR aIgnoreSingleBR) const;
1863 
1864   /**
1865    * SplitParagraph() splits the parent block, aParentDivOrP, at
1866    * aStartOfRightNode.
1867    *
1868    * @param aParentDivOrP       The parent block to be split.  This must be <p>
1869    *                            or <div> element.
1870    * @param aStartOfRightNode   The point to be start of right node after
1871    *                            split.  This must be descendant of
1872    *                            aParentDivOrP.
1873    * @param aNextBRNode         Next <br> node if there is.  Otherwise, nullptr.
1874    *                            If this is not nullptr, the <br> node may be
1875    *                            removed.
1876    */
1877   template <typename PT, typename CT>
1878   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SplitParagraph(
1879       Element& aParentDivOrP,
1880       const EditorDOMPointBase<PT, CT>& aStartOfRightNode, nsIContent* aBRNode);
1881 
1882   /**
1883    * HandleInsertParagraphInParagraph() does the right thing for Enter key
1884    * press or 'insertParagraph' command in aParentDivOrP.  aParentDivOrP will
1885    * be split at start of first selection range.
1886    *
1887    * @param aParentDivOrP   The parent block.  This must be <p> or <div>
1888    *                        element.
1889    * @return                Returns with NS_OK if this doesn't meat any
1890    *                        unexpected situation.  If this method tries to
1891    *                        split the paragraph, marked as handled.
1892    */
1893   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
1894   HandleInsertParagraphInParagraph(Element& aParentDivOrP);
1895 
1896   /**
1897    * HandleInsertParagraphInHeadingElement() handles insertParagraph command
1898    * (i.e., handling Enter key press) in a heading element.  This splits
1899    * aHeader element at aOffset in aNode.  Then, if right heading element is
1900    * empty, it'll be removed and new paragraph is created (its type is decided
1901    * with default paragraph separator).
1902    *
1903    * @param aHeader             The heading element to be split.
1904    * @param aNode               Typically, Selection start container,
1905    *                            where to be split.
1906    * @param aOffset             Typically, Selection start offset in the
1907    *                            start container, where to be split.
1908    */
1909   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1910   HandleInsertParagraphInHeadingElement(Element& aHeader, nsINode& aNode,
1911                                         int32_t aOffset);
1912 
1913   /**
1914    * HandleInsertParagraphInListItemElement() handles insertParagraph command
1915    * (i.e., handling Enter key press) in a list item element.
1916    *
1917    * @param aListItem           The list item which has the following point.
1918    * @param aNode               Typically, Selection start container, where to
1919    *                            insert a break.
1920    * @param aOffset             Typically, Selection start offset in the
1921    *                            start container, where to insert a break.
1922    */
1923   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1924   HandleInsertParagraphInListItemElement(Element& aListItem, nsINode& aNode,
1925                                          int32_t aOffset);
1926 
1927   /**
1928    * GetNearestAncestorListItemElement() returns a list item element if
1929    * aContent or its ancestor in editing host is one.  However, this won't
1930    * cross table related element.
1931    */
1932   Element* GetNearestAncestorListItemElement(nsIContent& aContent) const;
1933 
1934   /**
1935    * InsertParagraphSeparatorAsSubAction() handles insertPargraph commad
1936    * (i.e., handling Enter key press) with the above helper methods.
1937    */
1938   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
1939   InsertParagraphSeparatorAsSubAction();
1940 
1941   /**
1942    * Returns true if aNode1 or aNode2 or both is the descendant of some type of
1943    * table element, but their nearest table element ancestors differ.  "Table
1944    * element" here includes not just <table> but also <td>, <tbody>, <tr>, etc.
1945    * The nodes count as being their own descendants for this purpose, so a
1946    * table element is its own nearest table element ancestor.
1947    */
1948   static bool NodesInDifferentTableElements(nsINode& aNode1, nsINode& aNode2);
1949 
1950   /**
1951    * ChangeListElementType() replaces child list items of aListElement with
1952    * new list item element whose tag name is aNewListItemTag.
1953    * Note that if there are other list elements as children of aListElement,
1954    * this calls itself recursively even though it's invalid structure.
1955    *
1956    * @param aListElement        The list element whose list items will be
1957    *                            replaced.
1958    * @param aNewListTag         New list tag name.
1959    * @param aNewListItemTag     New list item tag name.
1960    * @return                    New list element or an error code if it fails.
1961    *                            New list element may be aListElement if its
1962    *                            tag name is same as aNewListTag.
1963    */
1964   [[nodiscard]] MOZ_CAN_RUN_SCRIPT CreateElementResult ChangeListElementType(
1965       Element& aListElement, nsAtom& aListType, nsAtom& aItemType);
1966 
1967   /**
1968    * ChangeSelectedHardLinesToList() converts selected ranges to specified
1969    * list element.  If there is different type of list elements, this method
1970    * converts them to specified list items too.  Basically, each hard line
1971    * will be wrapped with a list item element.  However, only when `<p>`
1972    * element is selected, its child `<br>` elements won't be treated as
1973    * hard line separators.  Perhaps, this is a bug.
1974    * NOTE: This method creates AutoSelectionRestorer.  Therefore, each caller
1975    *       need to check if the editor is still available even if this returns
1976    *       NS_OK.
1977    *
1978    * @param aListElementTagName         The new list element tag name.
1979    * @param aListItemElementTagName     The new list item element tag name.
1980    * @param aBulletType                 If this is not empty string, it's set
1981    *                                    to `type` attribute of new list item
1982    *                                    elements.  Otherwise, existing `type`
1983    *                                    attributes will be removed.
1984    * @param aSelectAllOfCurrentList     Yes if this should treat all of
1985    *                                    ancestor list element at selection.
1986    */
1987   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
1988   ChangeSelectedHardLinesToList(nsAtom& aListElementTagName,
1989                                 nsAtom& aListItemElementTagName,
1990                                 const nsAString& aBulletType,
1991                                 SelectAllOfCurrentList aSelectAllOfCurrentList);
1992 
1993   /**
1994    * MakeOrChangeListAndListItemAsSubAction() handles create list commands with
1995    * current selection.  If
1996    *
1997    * @param aListElementOrListItemElementTagName
1998    *                                    The new list element tag name or
1999    *                                    new list item tag name.
2000    *                                    If the former, list item tag name will
2001    *                                    be computed automatically.  Otherwise,
2002    *                                    list tag name will be computed.
2003    * @param aBulletType                 If this is not empty string, it's set
2004    *                                    to `type` attribute of new list item
2005    *                                    elements.  Otherwise, existing `type`
2006    *                                    attributes will be removed.
2007    * @param aSelectAllOfCurrentList     Yes if this should treat all of
2008    *                                    ancestor list element at selection.
2009    */
2010   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2011   MakeOrChangeListAndListItemAsSubAction(
2012       nsAtom& aListElementOrListItemElementTagName,
2013       const nsAString& aBulletType,
2014       SelectAllOfCurrentList aSelectAllOfCurrentList);
2015 
2016   /**
2017    * If aContent is a text node that contains only collapsed whitespace or empty
2018    * and editable.
2019    */
2020   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2021   DeleteNodeIfInvisibleAndEditableTextNode(nsIContent& aContent);
2022 
2023   /**
2024    * DeleteTextAndTextNodesWithTransaction() removes text nodes which are in
2025    * the given range and delete some characters in start and/or end of
2026    * the range.
2027    */
2028   template <typename EditorDOMPointType>
2029   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2030   DeleteTextAndTextNodesWithTransaction(const EditorDOMPointType& aStartPoint,
2031                                         const EditorDOMPointType& aEndPoint);
2032 
2033   /**
2034    * If aPoint follows invisible `<br>` element, returns the invisible `<br>`
2035    * element.  Otherwise, nullptr.
2036    */
2037   template <typename PT, typename CT>
2038   Element* GetInvisibleBRElementAt(const EditorDOMPointBase<PT, CT>& aPoint);
2039 
2040   /**
2041    * JoinNodesWithTransaction() joins aLeftNode and aRightNode.  Content of
2042    * aLeftNode will be merged into aRightNode.  Actual implemenation of this
2043    * method is JoinNodesImpl().  So, see its explanation for the detail.
2044    *
2045    * @param aLeftNode   Will be removed from the DOM tree.
2046    * @param aRightNode  The node which will be new container of the content of
2047    *                    aLeftNode.
2048    */
2049   MOZ_CAN_RUN_SCRIPT nsresult JoinNodesWithTransaction(nsINode& aLeftNode,
2050                                                        nsINode& aRightNode);
2051 
2052   /**
2053    * JoinNearestEditableNodesWithTransaction() joins two editable nodes which
2054    * are themselves or the nearest editable node of aLeftNode and aRightNode.
2055    * XXX This method's behavior is odd.  For example, if user types Backspace
2056    *     key at the second editable paragraph in this case:
2057    *     <div contenteditable>
2058    *       <p>first editable paragraph</p>
2059    *       <p contenteditable="false">non-editable paragraph</p>
2060    *       <p>second editable paragraph</p>
2061    *     </div>
2062    *     The first editable paragraph's content will be moved into the second
2063    *     editable paragraph and the non-editable paragraph becomes the first
2064    *     paragraph of the editor.  I don't think that it's expected behavior of
2065    *     any users...
2066    *
2067    * @param aLeftNode   The node which will be removed.
2068    * @param aRightNode  The node which will be inserted the content of
2069    *                    aLeftNode.
2070    * @param aNewFirstChildOfRightNode
2071    *                    [out] The point at the first child of aRightNode.
2072    */
2073   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2074   JoinNearestEditableNodesWithTransaction(
2075       nsIContent& aLeftNode, nsIContent& aRightNode,
2076       EditorDOMPoint* aNewFirstChildOfRightNode);
2077 
2078   /**
2079    * ReplaceContainerAndCloneAttributesWithTransaction() creates new element
2080    * whose name is aTagName, copies all attributes from aOldContainer to the
2081    * new element, moves all children in aOldContainer to the new element, then,
2082    * removes aOldContainer from the DOM tree.
2083    *
2084    * @param aOldContainer       The element node which should be replaced
2085    *                            with new element.
2086    * @param aTagName            The name of new element node.
2087    */
2088   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element>
ReplaceContainerAndCloneAttributesWithTransaction(Element & aOldContainer,nsAtom & aTagName)2089   ReplaceContainerAndCloneAttributesWithTransaction(Element& aOldContainer,
2090                                                     nsAtom& aTagName) {
2091     return ReplaceContainerWithTransactionInternal(
2092         aOldContainer, aTagName, *nsGkAtoms::_empty, EmptyString(), true);
2093   }
2094 
2095   /**
2096    * ReplaceContainerWithTransaction() creates new element whose name is
2097    * aTagName, sets aAttributes of the new element to aAttributeValue, moves
2098    * all children in aOldContainer to the new element, then, removes
2099    * aOldContainer from the DOM tree.
2100    *
2101    * @param aOldContainer       The element node which should be replaced
2102    *                            with new element.
2103    * @param aTagName            The name of new element node.
2104    * @param aAttribute          Attribute name to be set to the new element.
2105    * @param aAttributeValue     Attribute value to be set to aAttribute.
2106    */
ReplaceContainerWithTransaction(Element & aOldContainer,nsAtom & aTagName,nsAtom & aAttribute,const nsAString & aAttributeValue)2107   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> ReplaceContainerWithTransaction(
2108       Element& aOldContainer, nsAtom& aTagName, nsAtom& aAttribute,
2109       const nsAString& aAttributeValue) {
2110     return ReplaceContainerWithTransactionInternal(
2111         aOldContainer, aTagName, aAttribute, aAttributeValue, false);
2112   }
2113 
2114   /**
2115    * ReplaceContainerWithTransaction() creates new element whose name is
2116    * aTagName, moves all children in aOldContainer to the new element, then,
2117    * removes aOldContainer from the DOM tree.
2118    *
2119    * @param aOldContainer       The element node which should be replaced
2120    *                            with new element.
2121    * @param aTagName            The name of new element node.
2122    */
ReplaceContainerWithTransaction(Element & aOldContainer,nsAtom & aTagName)2123   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> ReplaceContainerWithTransaction(
2124       Element& aOldContainer, nsAtom& aTagName) {
2125     return ReplaceContainerWithTransactionInternal(
2126         aOldContainer, aTagName, *nsGkAtoms::_empty, EmptyString(), false);
2127   }
2128 
2129   /**
2130    * RemoveContainerWithTransaction() removes aElement from the DOM tree and
2131    * moves all its children to the parent of aElement.
2132    *
2133    * @param aElement            The element to be removed.
2134    */
2135   MOZ_CAN_RUN_SCRIPT nsresult RemoveContainerWithTransaction(Element& aElement);
2136 
2137   /**
2138    * InsertContainerWithTransaction() creates new element whose name is
2139    * aTagName, moves aContent into the new element, then, inserts the new
2140    * element into where aContent was.
2141    * Note that this method does not check if aContent is valid child of
2142    * the new element.  So, callers need to guarantee it.
2143    *
2144    * @param aContent            The content which will be wrapped with new
2145    *                            element.
2146    * @param aTagName            Element name of new element which will wrap
2147    *                            aContent and be inserted into where aContent
2148    *                            was.
2149    * @return                    The new element.
2150    */
InsertContainerWithTransaction(nsIContent & aContent,nsAtom & aTagName)2151   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> InsertContainerWithTransaction(
2152       nsIContent& aContent, nsAtom& aTagName) {
2153     return InsertContainerWithTransactionInternal(
2154         aContent, aTagName, *nsGkAtoms::_empty, EmptyString());
2155   }
2156 
2157   /**
2158    * InsertContainerWithTransaction() creates new element whose name is
2159    * aTagName, sets its aAttribute to aAttributeValue, moves aContent into the
2160    * new element, then, inserts the new element into where aContent was.
2161    * Note that this method does not check if aContent is valid child of
2162    * the new element.  So, callers need to guarantee it.
2163    *
2164    * @param aContent            The content which will be wrapped with new
2165    *                            element.
2166    * @param aTagName            Element name of new element which will wrap
2167    *                            aContent and be inserted into where aContent
2168    *                            was.
2169    * @param aAttribute          Attribute which should be set to the new
2170    *                            element.
2171    * @param aAttributeValue     Value to be set to aAttribute.
2172    * @return                    The new element.
2173    */
InsertContainerWithTransaction(nsIContent & aContent,nsAtom & aTagName,nsAtom & aAttribute,const nsAString & aAttributeValue)2174   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> InsertContainerWithTransaction(
2175       nsIContent& aContent, nsAtom& aTagName, nsAtom& aAttribute,
2176       const nsAString& aAttributeValue) {
2177     return InsertContainerWithTransactionInternal(aContent, aTagName,
2178                                                   aAttribute, aAttributeValue);
2179   }
2180 
2181   /**
2182    * MoveNodeWithTransaction() moves aContent to aPointToInsert.
2183    *
2184    * @param aContent        The node to be moved.
2185    */
2186   MOZ_CAN_RUN_SCRIPT nsresult MoveNodeWithTransaction(
2187       nsIContent& aContent, const EditorDOMPoint& aPointToInsert);
2188 
2189   /**
2190    * MoveNodeToEndWithTransaction() moves aContent to end of aNewContainer.
2191    *
2192    * @param aContent        The node to be moved.
2193    * @param aNewContainer   The new container which will contain aContent as
2194    *                        its last child.
2195    */
2196   MOZ_CAN_RUN_SCRIPT nsresult
MoveNodeToEndWithTransaction(nsIContent & aContent,nsINode & aNewContainer)2197   MoveNodeToEndWithTransaction(nsIContent& aContent, nsINode& aNewContainer) {
2198     EditorDOMPoint pointToInsert;
2199     pointToInsert.SetToEndOf(&aNewContainer);
2200     return MoveNodeWithTransaction(aContent, pointToInsert);
2201   }
2202 
2203   /**
2204    * MoveNodeOrChildrenWithTransaction() moves aContent to aPointToInsert.  If
2205    * cannot insert aContent due to invalid relation, moves only its children
2206    * recursively and removes aContent from the DOM tree.
2207    *
2208    * @param aContent            Content which should be moved.
2209    * @param aPointToInsert      The point to be inserted aContent or its
2210    *                            descendants.
2211    */
2212   [[nodiscard]] MOZ_CAN_RUN_SCRIPT MoveNodeResult
2213   MoveNodeOrChildrenWithTransaction(nsIContent& aNode,
2214                                     const EditorDOMPoint& aPointToInsert);
2215 
2216   /**
2217    * MoveChildrenWithTransaction() moves the children of aElement to
2218    * aPointToInsert.  If cannot insert some children due to invalid relation,
2219    * calls MoveNodeOrChildrenWithTransaction() to remove the children but keep
2220    * moving its children.
2221    *
2222    * @param aElement            Container element whose children should be
2223    *                            moved.
2224    * @param aPointToInsert      The point to be inserted children of aElement
2225    *                            or its descendants.
2226    */
2227   [[nodiscard]] MOZ_CAN_RUN_SCRIPT MoveNodeResult MoveChildrenWithTransaction(
2228       Element& aElement, const EditorDOMPoint& aPointToInsert);
2229 
2230   /**
2231    * MoveAllChildren() moves all children of aContainer to before
2232    * aPointToInsert.GetChild().
2233    * See explanation of MoveChildrenBetween() for the detail of the behavior.
2234    *
2235    * @param aContainer          The container node whose all children should
2236    *                            be moved.
2237    * @param aPointToInsert      The insertion point.  The container must not
2238    *                            be a data node like a text node.
2239    * @param aError              The result.  If this succeeds to move children,
2240    *                            returns NS_OK.  Otherwise, an error.
2241    */
2242   void MoveAllChildren(nsINode& aContainer,
2243                        const EditorRawDOMPoint& aPointToInsert,
2244                        ErrorResult& aError);
2245 
2246   /**
2247    * MoveChildrenBetween() moves all children between aFirstChild and aLastChild
2248    * to before aPointToInsert.GetChild(). If some children are moved to
2249    * different container while this method moves other children, they are just
2250    * ignored. If the child node referred by aPointToInsert is moved to different
2251    * container while this method moves children, returns error.
2252    *
2253    * @param aFirstChild         The first child which should be moved to
2254    *                            aPointToInsert.
2255    * @param aLastChild          The last child which should be moved.  This
2256    *                            must be a sibling of aFirstChild and it should
2257    *                            be positioned after aFirstChild in the DOM tree
2258    *                            order.
2259    * @param aPointToInsert      The insertion point.  The container must not
2260    *                            be a data node like a text node.
2261    * @param aError              The result.  If this succeeds to move children,
2262    *                            returns NS_OK.  Otherwise, an error.
2263    */
2264   void MoveChildrenBetween(nsIContent& aFirstChild, nsIContent& aLastChild,
2265                            const EditorRawDOMPoint& aPointToInsert,
2266                            ErrorResult& aError);
2267 
2268   /**
2269    * MovePreviousSiblings() moves all siblings before aChild (i.e., aChild
2270    * won't be moved) to before aPointToInsert.GetChild().
2271    * See explanation of MoveChildrenBetween() for the detail of the behavior.
2272    *
2273    * @param aChild              The node which is next sibling of the last
2274    *                            node to be moved.
2275    * @param aPointToInsert      The insertion point.  The container must not
2276    *                            be a data node like a text node.
2277    * @param aError              The result.  If this succeeds to move children,
2278    *                            returns NS_OK.  Otherwise, an error.
2279    */
2280   void MovePreviousSiblings(nsIContent& aChild,
2281                             const EditorRawDOMPoint& aPointToInsert,
2282                             ErrorResult& aError);
2283 
2284   /**
2285    * MoveOneHardLineContents() moves the content in a hard line which contains
2286    * aPointInHardLine to aPointToInsert or end of aPointToInsert's container.
2287    *
2288    * @param aPointInHardLine            A point in a hard line.  All nodes in
2289    *                                    same hard line will be moved.
2290    * @param aPointToInsert              Point to insert contents of the hard
2291    *                                    line.
2292    * @param aMoveToEndOfContainer       If `Yes`, aPointToInsert.Offset() will
2293    *                                    be ignored and instead, all contents
2294    *                                    will be appended to the container of
2295    *                                    aPointToInsert.  The result may be
2296    *                                    different from setting this to `No`
2297    *                                    and aPointToInsert points end of the
2298    *                                    container because mutation event
2299    *                                    listeners may modify children of the
2300    *                                    container while we're moving nodes.
2301    */
2302   enum class MoveToEndOfContainer { Yes, No };
2303   [[nodiscard]] MOZ_CAN_RUN_SCRIPT MoveNodeResult MoveOneHardLineContents(
2304       const EditorDOMPoint& aPointInHardLine,
2305       const EditorDOMPoint& aPointToInsert,
2306       MoveToEndOfContainer aMoveToEndOfContainer = MoveToEndOfContainer::No);
2307 
2308   /**
2309    * SplitNodeWithTransaction() creates a transaction to create a new node
2310    * (left node) identical to an existing node (right node), and split the
2311    * contents between the same point in both nodes, then, execute the
2312    * transaction.
2313    *
2314    * @param aStartOfRightNode   The point to split.  Its container will be
2315    *                            the right node, i.e., become the new node's
2316    *                            next sibling.  And the point will be start
2317    *                            of the right node.
2318    * @param aError              If succeed, returns no error.  Otherwise, an
2319    *                            error.
2320    */
2321   MOZ_CAN_RUN_SCRIPT already_AddRefed<nsIContent> SplitNodeWithTransaction(
2322       const EditorDOMPoint& aStartOfRightNode, ErrorResult& aResult);
2323 
2324   enum class SplitAtEdges {
2325     // SplitNodeDeepWithTransaction() won't split container element
2326     // nodes at their edges.  I.e., when split point is start or end of
2327     // container, it won't be split.
2328     eDoNotCreateEmptyContainer,
2329     // SplitNodeDeepWithTransaction() always splits containers even
2330     // if the split point is at edge of a container.  E.g., if split point is
2331     // start of an inline element, empty inline element is created as a new left
2332     // node.
2333     eAllowToCreateEmptyContainer,
2334   };
2335 
2336   /**
2337    * SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
2338    *
2339    * @param aMostAncestorToSplit        The most ancestor node which should be
2340    *                                    split.
2341    * @param aStartOfDeepestRightNode    The start point of deepest right node.
2342    *                                    This point must be descendant of
2343    *                                    aMostAncestorToSplit.
2344    * @param aSplitAtEdges               Whether the caller allows this to
2345    *                                    create empty container element when
2346    *                                    split point is start or end of an
2347    *                                    element.
2348    * @return                            SplitPoint() returns split point in
2349    *                                    aMostAncestorToSplit.  The point must
2350    *                                    be good to insert something if the
2351    *                                    caller want to do it.
2352    */
2353   MOZ_CAN_RUN_SCRIPT SplitNodeResult
2354   SplitNodeDeepWithTransaction(nsIContent& aMostAncestorToSplit,
2355                                const EditorDOMPoint& aDeepestStartOfRightNode,
2356                                SplitAtEdges aSplitAtEdges);
2357 
2358   /**
2359    * JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
2360    * First, they are joined simply, then, new right node is assumed as the
2361    * child at length of the left node before joined and new left node is
2362    * assumed as its previous sibling.  Then, they will be joined again.
2363    * And then, these steps are repeated.
2364    *
2365    * @param aLeftContent    The node which will be removed form the tree.
2366    * @param aRightContent   The node which will be inserted the contents of
2367    *                        aRightContent.
2368    * @return                The point of the first child of the last right node.
2369    *                        The result is always set if this succeeded.
2370    */
2371   MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2372   JoinNodesDeepWithTransaction(nsIContent& aLeftContent,
2373                                nsIContent& aRightContent);
2374 
2375   /**
2376    * TryToJoinBlocksWithTransaction() tries to join two block elements.  The
2377    * right element is always joined to the left element.  If the elements are
2378    * the same type and not nested within each other,
2379    * JoinEditableNodesWithTransaction() is called (example, joining two list
2380    * items together into one).  If the elements are not the same type, or one
2381    * is a descendant of the other, we instead destroy the right block placing
2382    * its children into leftblock.
2383    *
2384    * @return            Sets canceled to true if the operation should do
2385    *                    nothing anymore even if this doesn't join the blocks.
2386    *                    Sets handled to true if this actually handles the
2387    *                    request.  Note that this may set it to true even if this
2388    *                    does not join the block.  E.g., if the blocks shouldn't
2389    *                    be joined or it's impossible to join them but it's not
2390    *                    unexpected case, this returns true with this.
2391    */
2392   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2393   TryToJoinBlocksWithTransaction(nsIContent& aLeftContentInBlock,
2394                                  nsIContent& aRightContentInBlock);
2395 
2396   /**
2397    * GetGoodCaretPointFor() returns a good point to collapse `Selection`
2398    * after handling edit action with aDirectionAndAmount.
2399    *
2400    * @param aContent            The content where you want to put caret
2401    *                            around.
2402    * @param aDirectionAndAmount Muse be one of eNext, eNextWord, eToEndOfLine,
2403    *                            ePrevious, ePreviousWord and eToBeggingOfLine.
2404    *                            Set the direction of handled edit action.
2405    */
2406   EditorDOMPoint GetGoodCaretPointFor(
2407       nsIContent& aContent, nsIEditor::EDirection aDirectionAndAmount);
2408 
2409   /**
2410    * RemoveEmptyInclusiveAncestorInlineElements() removes empty inclusive
2411    * ancestor inline elements in inclusive ancestor block element of aContent.
2412    *
2413    * @param aContent    Must be an empty content.
2414    */
2415   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2416   RemoveEmptyInclusiveAncestorInlineElements(nsIContent& aContent);
2417 
2418   /**
2419    * MaybeDeleteTopMostEmptyAncestor() looks for top most empty block ancestor
2420    * of aStartContent in aEditingHostElement.
2421    * If found empty ancestor is a list item element, inserts a <br> element
2422    * before its parent element if grand parent is a list element.  Then,
2423    * collapse Selection to after the empty block.
2424    * If found empty ancestor is not a list item element, collapse Selection to
2425    * somewhere depending on aAction.
2426    * Finally, removes the empty block ancestor.
2427    *
2428    * @param aStartContent       Start content to look for empty ancestors.
2429    * @param aEditingHostElement Current editing host.
2430    * @param aDirectionAndAmount If found empty ancestor block is a list item
2431    *                            element, this is ignored.  Otherwise:
2432    *                            - If eNext, eNextWord or eToEndOfLine, collapse
2433    *                              Selection to after found empty ancestor.
2434    *                            - If ePrevious, ePreviousWord or
2435    *                              eToBeginningOfLine, collapse Selection to
2436    *                              end of previous editable node.
2437    *                            Otherwise, eNone is allowed but does nothing.
2438    */
2439   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2440   MaybeDeleteTopMostEmptyAncestor(nsIContent& aStartContent,
2441                                   Element& aEditingHostElement,
2442                                   nsIEditor::EDirection aDirectionAndAmount);
2443 
2444   /**
2445    * GetRangeExtendedToIncludeInvisibleNodes() returns extended range.
2446    * If there are some invisible nodes around aAbstractRange, they may
2447    * be included.
2448    *
2449    * @param aAbstractRange      Original range.  This must not be collapsed
2450    *                            and must be positioned.
2451    * @return                    Extended range.
2452    */
2453   already_AddRefed<dom::StaticRange> GetRangeExtendedToIncludeInvisibleNodes(
2454       const dom::AbstractRange& aAbstractRange);
2455 
2456   /**
2457    * HandleDeleteCollapsedSelectionAtWhiteSpaces() handles deletion of
2458    * collapsed selection at whitespaces in a text node.
2459    *
2460    * @param aDirectionAndAmount Direction of the deletion.
2461    * @param aWSRunObjectAtCaret WSRunObject instance which was initialized with
2462    *                            the caret point.
2463    */
2464   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2465   HandleDeleteCollapsedSelectionAtWhiteSpaces(
2466       nsIEditor::EDirection aDirectionAndAmount,
2467       WSRunObject& aWSRunObjectAtCaret);
2468 
2469   /**
2470    * HandleDeleteCollapsedSelectionAtTextNode() handles deletion of
2471    * collapsed selection in a text node.
2472    *
2473    * @param aDirectionAndAmount Direction of the deletion.
2474    * @param aPointToDelete      The point in a text node to delete character(s).
2475    *                            Caller must guarantee that this is in a text
2476    *                            node.
2477    */
2478   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2479   HandleDeleteCollapsedSelectionAtTextNode(
2480       nsIEditor::EDirection aDirectionAndAmount,
2481       const EditorDOMPoint& aPointToDelete);
2482 
2483   /**
2484    * HandleDeleteCollapsedSelectionAtAtomicContent() handles deletion of
2485    * atomic elements like `<br>`, `<hr>`, `<img>`, `<input>`, etc and
2486    * data nodes except text node (e.g., comment node).
2487    * If aAtomicContent is a invisible `<br>` element, this will call
2488    * `WillDeleteSelection()` recursively after deleting it.
2489    *
2490    * @param aDirectionAndAmount Direction of the deletion.
2491    * @param aStripWrappers      Must be eStrip or eNoStrip.
2492    * @param aAtomicContent      The atomic content to be deleted.
2493    * @param aCaretPoint         The caret point (i.e., selection start or
2494    *                            end).
2495    * @param aWSRunScannerAtCaret WSRunScanner instance which was initialized
2496    *                             with the caret point.
2497    */
2498   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2499   HandleDeleteCollapsedSelectionAtAtomicContent(
2500       nsIEditor::EDirection aDirectionAndAmount,
2501       nsIEditor::EStripWrappers aStripWrappers, nsIContent& aAtomicContent,
2502       const EditorDOMPoint& aCaretPoint, WSRunScanner& aWSRunScannerAtCaret);
2503 
2504   /**
2505    * HandleDeleteCollapsedSelectionAtOtherBlockBoundary() handles deletion at
2506    * other block boundary (i.e., immediately before or after a block).
2507    * If this does not join blocks, `WillDeleteSelection()` may be called
2508    * recursively.
2509    *
2510    * @param aDirectionAndAmount Direction of the deletion.
2511    * @param aStripWrappers      Must be eStrip or eNoStrip.
2512    * @param aOtherBlockElement  The block element which follows the caret or
2513    *                            is followed by caret.
2514    * @param aCaretPoint         The caret point (i.e., selection start or
2515    *                            end).
2516    * @param aWSRunScannerAtCaret WSRunScanner instance which was initialized
2517    *                             with the caret point.
2518    */
2519   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2520   HandleDeleteCollapsedSelectionAtOtherBlockBoundary(
2521       nsIEditor::EDirection aDirectionAndAmount,
2522       nsIEditor::EStripWrappers aStripWrappers, Element& aOtherBlockElement,
2523       const EditorDOMPoint& aCaretPoint, WSRunScanner& aWSRunScannerAtCaret);
2524 
2525   /**
2526    * HandleDeleteCollapsedSelectionAtCurrentBlockBoundary() handles deletion
2527    * at current block boundary (i.e., at start or end of current block).
2528    *
2529    * @param aDirectionAndAmount         Direction of the deletion.
2530    * @param aCurrentBlockElement        The current block element.
2531    * @param aCaretPoint                 The caret point (i.e., selection start
2532    *                                    or end).
2533    */
2534   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2535   HandleDeleteCollapsedSelectionAtCurrentBlockBoundary(
2536       nsIEditor::EDirection aDirectionAndAmount, Element& aCurrentBlockElement,
2537       const EditorDOMPoint& aCaretPoint);
2538 
2539   /**
2540    * DeleteUnnecessaryNodesAndCollapseSelection() removes unnecessary nodes
2541    * around aSelectionStartPoint and aSelectionEndPoint.  Then, collapse
2542    * selection at aSelectionStartPoint or aSelectionEndPoint (depending on
2543    * aDirectionAndAmount).
2544    *
2545    * @param aDirectionAndAmount         Direction of the deletion.
2546    *                                    If nsIEditor::ePrevious, selection will
2547    *                                    be collapsed to aSelectionEndPoint.
2548    *                                    Otherwise, selection will be collapsed
2549    *                                    to aSelectionStartPoint.
2550    * @param aSelectionStartPoint        First selection range start after
2551    *                                    computing the deleting range.
2552    * @param aSelectionEndPoint          First selection range end after
2553    *                                    computing the deleting range.
2554    */
2555   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2556   DeleteUnnecessaryNodesAndCollapseSelection(
2557       nsIEditor::EDirection aDirectionAndAmount,
2558       const EditorDOMPoint& aSelectionStartPoint,
2559       const EditorDOMPoint& aSelectionEndPoint);
2560 
2561   /**
2562    * HandleDeleteAroundCollapsedSelection() handles deletion with collapsed
2563    * `Selection`.  Callers must guarantee that this is called only when
2564    * `Selection` is collapsed.
2565    *
2566    * @param aDirectionAndAmount Direction of the deletion.
2567    * @param aStripWrappers      Must be eStrip or eNoStrip.
2568    */
2569   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2570   HandleDeleteAroundCollapsedSelection(
2571       nsIEditor::EDirection aDirectionAndAmount,
2572       nsIEditor::EStripWrappers aStripWrappers);
2573 
2574   /**
2575    * HandleDeleteNonCollapsedSelection() handles deletion with non-collapsed
2576    * `Selection`.  Callers must guarantee that this is called only when
2577    * `Selection` is NOT collapsed.
2578    *
2579    * @param aDirectionAndAmount         Direction of the deletion.
2580    * @param aStripWrappers              Must be eStrip or eNoStrip.
2581    * @param aSelectionWasCollpased      If the caller extended `Selection`
2582    *                                    from collapsed, set this to `Yes`.
2583    *                                    Otherwise, i.e., `Selection` is not
2584    *                                    collapsed from the beginning, set
2585    *                                    this to `No`.
2586    */
2587   enum class SelectionWasCollapsed { Yes, No };
2588   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2589   HandleDeleteNonCollapsedSelection(
2590       nsIEditor::EDirection aDirectionAndAmount,
2591       nsIEditor::EStripWrappers aStripWrappers,
2592       SelectionWasCollapsed aSelectionWasCollapsed);
2593 
2594   /**
2595    * DeleteElementsExceptTableRelatedElements() removes elements except
2596    * table related elements (except <table> itself) and their contents
2597    * from the DOM tree.
2598    *
2599    * @param aNode               If this is not a table related element, this
2600    *                            node will be removed from the DOM tree.
2601    *                            Otherwise, this method calls itself recursively
2602    *                            with its children.
2603    *
2604    */
2605   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2606   DeleteElementsExceptTableRelatedElements(nsINode& aNode);
2607 
2608   /**
2609    * HandleDeleteSelectionInternal() is a helper method of
2610    * HandleDeleteSelection().  This can be called recursively by the helper
2611    * methods.
2612    * NOTE: This method creates SelectionBatcher.  Therefore, each caller
2613    *       needs to check if the editor is still available even if this returns
2614    *       NS_OK.
2615    */
2616   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2617   HandleDeleteSelectionInternal(nsIEditor::EDirection aDirectionAndAmount,
2618                                 nsIEditor::EStripWrappers aStripWrappers);
2619 
2620   /**
2621    * This method handles "delete selection" commands.
2622    * NOTE: Don't call this method recursively from the helper methods since
2623    *       when nobody handled it without canceling and returing an error,
2624    *       this falls it back to `DeleteSelectionWithTransaction()`.
2625    *
2626    * @param aDirectionAndAmount Direction of the deletion.
2627    * @param aStripWrappers      Must be eStrip or eNoStrip.
2628    */
2629   [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual EditActionResult
2630   HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
2631                         nsIEditor::EStripWrappers aStripWrappers) final;
2632 
2633   /**
2634    * DeleteMostAncestorMailCiteElementIfEmpty() deletes most ancestor
2635    * mail cite element (`<blockquote type="cite">` or
2636    * `<span _moz_quote="true">`, the former can be created with middle click
2637    * paste with `Control` or `Command` even in the web) of aContent if it
2638    * becomes empty.
2639    */
2640   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2641   DeleteMostAncestorMailCiteElementIfEmpty(nsIContent& aContent);
2642 
2643   /**
2644    * LiftUpListItemElement() moves aListItemElement outside its parent.
2645    * If it's in a middle of a list element, the parent list element is split
2646    * before aListItemElement.  Then, moves aListItemElement to before its
2647    * parent list element.  I.e., moves aListItemElement between the 2 list
2648    * elements if original parent was split.  Then, if new parent becomes not a
2649    * list element, the list item element is removed and its contents are moved
2650    * to where the list item element was.  If aListItemElement becomse not a
2651    * child of list element, its contents are unwrapped from aListItemElement.
2652    *
2653    * @param aListItemElement    Must be a <li>, <dt> or <dd> element.
2654    * @param aLiftUpFromAllParentListElements
2655    *                            If Yes, this method calls itself recursively
2656    *                            to unwrap the contents in aListItemElement
2657    *                            from any ancestor list elements.
2658    *                            XXX This checks only direct parent of list
2659    *                                elements.  Therefore, if a parent list
2660    *                                element in a list item element, the
2661    *                                list item element and its list element
2662    *                                won't be unwrapped.
2663    */
2664   enum class LiftUpFromAllParentListElements { Yes, No };
2665   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult LiftUpListItemElement(
2666       dom::Element& aListItemElement,
2667       LiftUpFromAllParentListElements aLiftUpFromAllParentListElements);
2668 
2669   /**
2670    * DestroyListStructureRecursively() destroys the list structure of
2671    * aListElement recursively.
2672    * If aListElement has <li>, <dl> or <dt> as a child, the element is removed
2673    * but its descendants are moved to where the list item element was.
2674    * If aListElement has another <ul>, <ol> or <dl> as a child, this method is
2675    * called recursively.
2676    * If aListElement has other nodes as its child, they are just removed.
2677    * Finally, aListElement is removed. and its all children are moved to
2678    * where the aListElement was.
2679    *
2680    * @param aListElement        A <ul>, <ol> or <dl> element.
2681    */
2682   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2683   DestroyListStructureRecursively(Element& aListElement);
2684 
2685   /**
2686    * RemoveListAtSelectionAsSubAction() removes list elements and list item
2687    * elements at Selection.  And move contents in them where the removed list
2688    * was.
2689    */
2690   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveListAtSelectionAsSubAction();
2691 
2692   /**
2693    * ChangeMarginStart() changes margin of aElement to indent or outdent.
2694    * If it's rtl text, margin-right will be changed.  Otherwise, margin-left.
2695    * XXX This is not aware of vertical writing-mode.
2696    */
2697   enum class ChangeMargin { Increase, Decrease };
2698   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2699   ChangeMarginStart(Element& aElement, ChangeMargin aChangeMargin);
2700 
2701   /**
2702    * HandleCSSIndentAtSelectionInternal() indents around Selection with CSS.
2703    * This method creates AutoSelectionRestorer.  Therefore, each caller
2704    * need to check if the editor is still available even if this returns
2705    * NS_OK.
2706    * NOTE: Use HandleCSSIndentAtSelection() instead.
2707    */
2708   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2709   HandleCSSIndentAtSelectionInternal();
2710 
2711   /**
2712    * HandleHTMLIndentAtSelectionInternal() indents around Selection with HTML.
2713    * This method creates AutoSelectionRestorer.  Therefore, each caller
2714    * need to check if the editor is still available even if this returns
2715    * NS_OK.
2716    * NOTE: Use HandleHTMLIndentAtSelection() instead.
2717    */
2718   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2719   HandleHTMLIndentAtSelectionInternal();
2720 
2721   /**
2722    * HandleCSSIndentAtSelection() indents around Selection with CSS.
2723    * NOTE: This is a helper method of `HandleIndentAtSelection()`.  If you
2724    *       want to call this directly, you should check whether you need
2725    *       do do something which `HandleIndentAtSelection()` does.
2726    */
2727   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandleCSSIndentAtSelection();
2728 
2729   /**
2730    * HandleHTMLIndentAtSelection() indents around Selection with HTML.
2731    * NOTE: This is a helper method of `HandleIndentAtSelection()`.  If you
2732    *       want to call this directly, you should check whether you need
2733    *       do do something which `HandleIndentAtSelection()` does.
2734    */
2735   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandleHTMLIndentAtSelection();
2736 
2737   /**
2738    * HandleIndentAtSelection() indents around Selection with HTML or CSS.
2739    */
2740   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult HandleIndentAtSelection();
2741 
2742   /**
2743    * OutdentPartOfBlock() outdents the nodes between aStartOfOutdent and
2744    * aEndOfOutdent.  This splits the range off from aBlockElement first.
2745    * Then, removes the middle element if aIsBlockIndentedWithCSS is false.
2746    * Otherwise, decreases the margin of the middle element.
2747    *
2748    * @param aBlockElement       A block element which includes both
2749    *                            aStartOfOutdent and aEndOfOutdent.
2750    * @param aStartOfOutdent     First node which is descendant of
2751    *                            aBlockElement will be outdented.
2752    * @param aEndOfOutdent       Last node which is descandant of
2753    *                            aBlockElement will be outdented.
2754    * @param aBlockIndentedWith  `CSS` if aBlockElement is indented with
2755    *                            CSS margin property.
2756    *                            `HTML` if aBlockElement is `<blockquote>`
2757    *                            or something.
2758    * @return                    The left content is new created element
2759    *                            splitting before aStartOfOutdent.
2760    *                            The right content is existing element.
2761    *                            The middle content is outdented element
2762    *                            if aBlockIndentedWith is `CSS`.
2763    *                            Otherwise, nullptr.
2764    */
2765   enum class BlockIndentedWith { CSS, HTML };
2766   [[nodiscard]] MOZ_CAN_RUN_SCRIPT SplitRangeOffFromNodeResult
2767   OutdentPartOfBlock(Element& aBlockElement, nsIContent& aStartOfOutdent,
2768                      nsIContent& aEndOutdent,
2769                      BlockIndentedWith aBlockIndentedWith);
2770 
2771   /**
2772    * HandleOutdentAtSelectionInternal() outdents contents around Selection.
2773    * This method creates AutoSelectionRestorer.  Therefore, each caller
2774    * needs to check if the editor is still available even if this returns
2775    * NS_OK.
2776    * NOTE: Call `HandleOutdentAtSelection()` instead.
2777    *
2778    * @return                    The left content is left content of last
2779    *                            outdented element.
2780    *                            The right content is right content of last
2781    *                            outdented element.
2782    *                            The middle content is middle content of last
2783    *                            outdented element.
2784    */
2785   [[nodiscard]] MOZ_CAN_RUN_SCRIPT SplitRangeOffFromNodeResult
2786   HandleOutdentAtSelectionInternal();
2787 
2788   /**
2789    * HandleOutdentAtSelection() outdents contents around Selection.
2790    */
2791   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult HandleOutdentAtSelection();
2792 
2793   /**
2794    * AlignBlockContentsWithDivElement() sets align attribute of <div> element
2795    * which is only child of aBlockElement to aAlignType.  If aBlockElement
2796    * has 2 or more children or does not have a `<div>` element, inserts a
2797    * new `<div>` element into aBlockElement and move all children of
2798    * aBlockElement into the new `<div>` element.
2799    *
2800    * @param aBlockElement       The element node whose contents should be
2801    *                            aligned to aAlignType.  This should be
2802    *                            an element which can have `<div>` element
2803    *                            as its child.
2804    * @param aAlignType          New value of align attribute of `<div>`
2805    *                            element.
2806    */
2807   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult AlignBlockContentsWithDivElement(
2808       dom::Element& aBlockElement, const nsAString& aAlignType);
2809 
2810   /**
2811    * AlignContentsInAllTableCellsAndListItems() calls
2812    * AlignBlockContentsWithDivElement() for aligning contents in every list
2813    * item element and table cell element in aElement.
2814    *
2815    * @param aElement            The node which is or whose descendants should
2816    *                            be aligned to aAlignType.
2817    * @param aAlignType          New value of `align` attribute of `<div>`.
2818    */
2819   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2820   AlignContentsInAllTableCellsAndListItems(dom::Element& aElement,
2821                                            const nsAString& aAlignType);
2822 
2823   /**
2824    * MakeTransitionList() detects all the transitions in the array, where a
2825    * transition means that adjacent nodes in the array don't have the same
2826    * parent.
2827    */
2828   static void MakeTransitionList(
2829       const nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
2830       nsTArray<bool>& aTransitionArray);
2831 
2832   /**
2833    * EnsureHardLineBeginsWithFirstChildOf() inserts `<br>` element before
2834    * first child of aRemovingContainerElement if it will not be start of a
2835    * hard line after removing aRemovingContainerElement.
2836    */
2837   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2838   EnsureHardLineBeginsWithFirstChildOf(dom::Element& aRemovingContainerElement);
2839 
2840   /**
2841    * EnsureHardLineEndsWithLastChildOf() inserts `<br>` element after last
2842    * child of aRemovingContainerElement if it will not be end of a hard line
2843    * after removing aRemovingContainerElement.
2844    */
2845   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2846   EnsureHardLineEndsWithLastChildOf(dom::Element& aRemovingContainerElement);
2847 
2848   /**
2849    * RemoveAlignFromDescendants() removes align attributes, text-align
2850    * properties and <center> elements in aElement.
2851    *
2852    * @param aElement    Alignment information of the node and/or its
2853    *                    descendants will be removed.
2854    *                    NOTE: aElement must not be a `<table>` element.
2855    * @param aAlignType  New align value to be set only when it's in
2856    *                    CSS mode and this method meets <table> or <hr>.
2857    *                    XXX This is odd and not clear when you see caller of
2858    *                    this method.  Do you have better idea?
2859    * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only
2860    *                    descendants of aElement.
2861    *                    If `NodeAndDescendantsExceptTable`, modifies `aElement`
2862    *                    and its descendants.
2863    */
2864   enum class EditTarget {
2865     OnlyDescendantsExceptTable,
2866     NodeAndDescendantsExceptTable
2867   };
2868   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveAlignFromDescendants(
2869       Element& aElement, const nsAString& aAlignType, EditTarget aEditTarget);
2870 
2871   /**
2872    * SetBlockElementAlign() resets `align` attribute, `text-align` property
2873    * of descendants of aBlockOrHRElement except `<table>` element descendants.
2874    * Then, set `align` attribute or `text-align` property of aBlockOrHRElement.
2875    *
2876    * @param aBlockOrHRElement   The element whose contents will be aligned.
2877    *                            This must be a block element or `<hr>` element.
2878    *                            If we're not in CSS mode, this element has
2879    *                            to support `align` attribute (i.e.,
2880    *                            `HTMLEditUtils::SupportsAlignAttr()` must
2881    *                            return true).
2882    * @param aAlignType          Boundary or "center" which contents should be
2883    *                            aligned on.
2884    * @param aEditTarget         If `OnlyDescendantsExceptTable`, modifies only
2885    *                            descendants of aBlockOrHRElement.
2886    *                            If `NodeAndDescendantsExceptTable`, modifies
2887    *                            aBlockOrHRElement and its descendants.
2888    */
2889   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2890   SetBlockElementAlign(Element& aBlockOrHRElement, const nsAString& aAlignType,
2891                        EditTarget aEditTarget);
2892 
2893   /**
2894    * AlignContentsAtSelectionWithEmptyDivElement() inserts new `<div>` element
2895    * at `Selection` to align selected contents.  This returns as "handled"
2896    * if this modifies `Selection` so that callers shouldn't modify `Selection`
2897    * in such case especially when using AutoSelectionRestorer.
2898    *
2899    * @param aAlignType          New align attribute value where the contents
2900    *                            should be aligned to.
2901    */
2902   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2903   AlignContentsAtSelectionWithEmptyDivElement(const nsAString& aAlignType);
2904 
2905   /**
2906    * AlignNodesAndDescendants() make contents of nodes in aArrayOfContents and
2907    * their descendants aligned to aAlignType.
2908    *
2909    * @param aAlignType          New align attribute value where the contents
2910    *                            should be aligned to.
2911    */
2912   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult AlignNodesAndDescendants(
2913       nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
2914       const nsAString& aAlignType);
2915 
2916   /**
2917    * AlignContentsAtSelection() aligns contents around Selection to aAlignType.
2918    * This creates AutoSelectionRestorer.  Therefore, even if this returns
2919    * NS_OK, we might have been destroyed.  So, every caller needs to check if
2920    * Destroyed() returns false before modifying the DOM tree or changing
2921    * Selection.
2922    * NOTE: Call AlignAsSubAction() instead.
2923    *
2924    * @param aAlignType          New align attribute value where the contents
2925    *                            should be aligned to.
2926    */
2927   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2928   AlignContentsAtSelection(const nsAString& aAlignType);
2929 
2930   /**
2931    * AlignAsSubAction() handles "align" command with `Selection`.
2932    *
2933    * @param aAlignType          New align attribute value where the contents
2934    *                            should be aligned to.
2935    */
2936   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
2937   AlignAsSubAction(const nsAString& aAlignType);
2938 
2939   /**
2940    * StartOrEndOfSelectionRangesIsIn() returns true if start or end of one
2941    * of selection ranges is in aContent.
2942    */
2943   bool StartOrEndOfSelectionRangesIsIn(nsIContent& aContent) const;
2944 
2945   /**
2946    * FindNearEditableContent() tries to find an editable node near aPoint.
2947    *
2948    * @param aPoint      The DOM point where to start to search from.
2949    * @param aDirection  If nsIEditor::ePrevious is set, this searches an
2950    *                    editable node from next nodes.  Otherwise, from
2951    *                    previous nodes.
2952    * @return            If found, returns non-nullptr.  Otherwise, nullptr.
2953    *                    Note that if found node is in different table element,
2954    *                    this returns nullptr.
2955    *                    And also if aDirection is not nsIEditor::ePrevious,
2956    *                    the result may be the node pointed by aPoint.
2957    */
2958   template <typename PT, typename CT>
2959   nsIContent* FindNearEditableContent(const EditorDOMPointBase<PT, CT>& aPoint,
2960                                       nsIEditor::EDirection aDirection);
2961 
2962   /**
2963    * AdjustCaretPositionAndEnsurePaddingBRElement() may adjust caret
2964    * position to nearest editable content and if padding `<br>` element is
2965    * necessary at caret position, this creates it.
2966    *
2967    * @param aDirectionAndAmount Direction of the edit action.
2968    */
2969   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2970   AdjustCaretPositionAndEnsurePaddingBRElement(
2971       nsIEditor::EDirection aDirectionAndAmount);
2972 
2973   /**
2974    * EnsureSelectionInBodyOrDocumentElement() collapse `Selection` to the
2975    * primary `<body>` element or document element when `Selection` crosses
2976    * `<body>` element's boundary.
2977    */
2978   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2979   EnsureSelectionInBodyOrDocumentElement();
2980 
2981   /**
2982    * InsertBRElementToEmptyListItemsAndTableCellsInRange() inserts
2983    * `<br>` element into empty list item or table cell elements between
2984    * aStartRef and aEndRef.
2985    */
2986   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2987   InsertBRElementToEmptyListItemsAndTableCellsInRange(
2988       const RawRangeBoundary& aStartRef, const RawRangeBoundary& aEndRef);
2989 
2990   /**
2991    * RemoveEmptyNodesIn() removes all empty nodes in aRange.  However, if
2992    * mail-cite node has only a `<br>` element, the node will be removed
2993    * but <br> element is moved to where the mail-cite node was.
2994    * XXX This method is expensive if aRange is too wide and may remove
2995    *     unexpected empty element, e.g., it was created by JS, but we haven't
2996    *     touched it.  Cannot we remove this method and make guarantee that
2997    *     empty nodes won't be created?
2998    *
2999    * @param aRange      Must be positioned.
3000    */
3001   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveEmptyNodesIn(nsRange& aRange);
3002 
3003   /**
3004    * SetSelectionInterlinePosition() may set interline position if caret is
3005    * positioned around `<br>` or block boundary.  Don't call this when
3006    * `Selection` is not collapsed.
3007    */
3008   void SetSelectionInterlinePosition();
3009 
3010   /**
3011    * EnsureSelectionInBlockElement() may move caret into aElement or its
3012    * parent block if caret is outside of them.  Don't call this when
3013    * `Selection` is not collapsed.
3014    */
3015   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3016   EnsureCaretInBlockElement(dom::Element& aElement);
3017 
3018   /**
3019    * Called by `HTMLEditor::OnEndHandlingTopLevelEditSubAction()`.  This may
3020    * adjust Selection, remove unnecessary empty nodes, create `<br>` elements
3021    * if needed, etc.
3022    */
3023   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3024   OnEndHandlingTopLevelEditSubActionInternal();
3025 
3026   /**
3027    * MoveSelectedContentsToDivElementToMakeItAbsolutePosition() looks for
3028    * a `<div>` element in selection first.  If not, creates new `<div>`
3029    * element.  Then, move all selected contents into the target `<div>`
3030    * element.
3031    * Note that this creates AutoSelectionRestorer.  Therefore, callers need
3032    * to check whether we have been destroyed even when this returns NS_OK.
3033    *
3034    * @param aTargetElement      Returns target `<div>` element which should be
3035    *                            changed to absolute positioned.
3036    */
3037   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3038   MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
3039       RefPtr<Element>* aTargetElement);
3040 
3041   /**
3042    * SetSelectionToAbsoluteAsSubAction() move selected contents to first
3043    * selected `<div>` element or newly created `<div>` element and make
3044    * the `<div>` element positioned absolutely.
3045    * mNewBlockElement of TopLevelEditSubActionData will be set to the `<div>`
3046    * element.
3047    */
3048   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
3049   SetSelectionToAbsoluteAsSubAction();
3050 
3051   /**
3052    * SetSelectionToStaticAsSubAction() sets the `position` property of a
3053    * selection parent's block whose `position` is `absolute` to `static`.
3054    */
3055   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
3056   SetSelectionToStaticAsSubAction();
3057 
3058   /**
3059    * AddZIndexAsSubAction() adds aChange to `z-index` of nearest parent
3060    * absolute-positioned element from current selection.
3061    *
3062    * @param aChange     Amount to change `z-index`.
3063    */
3064   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
3065   AddZIndexAsSubAction(int32_t aChange);
3066 
3067   /**
3068    * OnDocumentModified() is called when editor content is changed.
3069    */
3070   MOZ_CAN_RUN_SCRIPT nsresult OnDocumentModified();
3071 
3072  protected:  // Called by helper classes.
3073   MOZ_CAN_RUN_SCRIPT virtual void OnStartToHandleTopLevelEditSubAction(
3074       EditSubAction aTopLevelEditSubAction,
3075       nsIEditor::EDirection aDirectionOfTopLevelEditSubAction,
3076       ErrorResult& aRv) override;
3077   MOZ_CAN_RUN_SCRIPT virtual nsresult OnEndHandlingTopLevelEditSubAction()
3078       override;
3079 
3080  protected:  // Shouldn't be used by friend classes
3081   virtual ~HTMLEditor();
3082 
3083   template <typename PT, typename CT>
3084   [[nodiscard]] MOZ_CAN_RUN_SCRIPT MOZ_NEVER_INLINE_DEBUG nsresult
CollapseSelectionTo(const EditorDOMPointBase<PT,CT> & aPoint)3085   CollapseSelectionTo(const EditorDOMPointBase<PT, CT>& aPoint) {
3086     ErrorResult error;
3087     CollapseSelectionTo(aPoint, error);
3088     return error.StealNSResult();
3089   }
3090 
3091   template <typename PT, typename CT>
CollapseSelectionTo(const EditorDOMPointBase<PT,CT> & aPoint,ErrorResult & aRv)3092   MOZ_CAN_RUN_SCRIPT MOZ_NEVER_INLINE_DEBUG void CollapseSelectionTo(
3093       const EditorDOMPointBase<PT, CT>& aPoint, ErrorResult& aRv) {
3094     MOZ_ASSERT(IsEditActionDataAvailable());
3095     MOZ_ASSERT(!aRv.Failed());
3096 
3097     SelectionRefPtr()->Collapse(aPoint, aRv);
3098     if (NS_WARN_IF(Destroyed())) {
3099       aRv = NS_ERROR_EDITOR_DESTROYED;
3100       return;
3101     }
3102     NS_WARNING_ASSERTION(!aRv.Failed(), "Selection::Collapse() failed");
3103   }
3104 
3105   [[nodiscard]] MOZ_CAN_RUN_SCRIPT MOZ_NEVER_INLINE_DEBUG nsresult
CollapseSelectionToStartOf(nsINode & aNode)3106   CollapseSelectionToStartOf(nsINode& aNode) {
3107     return CollapseSelectionTo(EditorRawDOMPoint(&aNode, 0));
3108   }
3109 
CollapseSelectionToStartOf(nsINode & aNode,ErrorResult & aRv)3110   MOZ_CAN_RUN_SCRIPT MOZ_NEVER_INLINE_DEBUG void CollapseSelectionToStartOf(
3111       nsINode& aNode, ErrorResult& aRv) {
3112     CollapseSelectionTo(EditorRawDOMPoint(&aNode, 0), aRv);
3113   }
3114 
3115   /**
3116    * InitEditorContentAndSelection() may insert `<br>` elements and padding
3117    * `<br>` elements if they are required for `<body>` or document element.
3118    * And collapse selection at the end if there is no selection ranges.
3119    * XXX I think that this should work with active editing host unless
3120    *     all over the document is ediable (i.e., in design mode or `<body>`
3121    *     or `<html>` has `contenteditable` attribute).
3122    */
3123   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InitEditorContentAndSelection();
3124 
3125   MOZ_CAN_RUN_SCRIPT virtual nsresult SelectAllInternal() override;
3126 
3127   /**
3128    * SelectContentInternal() sets Selection to aContentToSelect to
3129    * aContentToSelect + 1 in parent of aContentToSelect.
3130    *
3131    * @param aContentToSelect    The content which should be selected.
3132    */
3133   MOZ_CAN_RUN_SCRIPT nsresult
3134   SelectContentInternal(nsIContent& aContentToSelect);
3135 
3136   /**
3137    * CollapseSelectionAfter() collapses Selection after aElement.
3138    * If aElement is an orphan node or not in editing host, returns error.
3139    */
3140   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3141   CollapseSelectionAfter(Element& aElement);
3142 
3143   /**
3144    * GetInclusiveAncestorByTagNameAtSelection() looks for an element node whose
3145    * name matches aTagName from anchor node of Selection to <body> element.
3146    *
3147    * @param aTagName        The tag name which you want to look for.
3148    *                        Must not be nsGkAtoms::_empty.
3149    *                        If nsGkAtoms::list, the result may be <ul>, <ol> or
3150    *                        <dl> element.
3151    *                        If nsGkAtoms::td, the result may be <td> or <th>.
3152    *                        If nsGkAtoms::href, the result may be <a> element
3153    *                        which has "href" attribute with non-empty value.
3154    *                        If nsGkAtoms::anchor, the result may be <a> which
3155    *                        has "name" attribute with non-empty value.
3156    * @return                If an element which matches aTagName, returns
3157    *                        an Element.  Otherwise, nullptr.
3158    */
3159   Element* GetInclusiveAncestorByTagNameAtSelection(
3160       const nsStaticAtom& aTagName) const;
3161 
3162   /**
3163    * GetInclusiveAncestorByTagNameInternal() looks for an element node whose
3164    * name matches aTagName from aNode to <body> element.
3165    *
3166    * @param aTagName        The tag name which you want to look for.
3167    *                        Must not be nsGkAtoms::_empty.
3168    *                        If nsGkAtoms::list, the result may be <ul>, <ol> or
3169    *                        <dl> element.
3170    *                        If nsGkAtoms::td, the result may be <td> or <th>.
3171    *                        If nsGkAtoms::href, the result may be <a> element
3172    *                        which has "href" attribute with non-empty value.
3173    *                        If nsGkAtoms::anchor, the result may be <a> which
3174    *                        has "name" attribute with non-empty value.
3175    * @param aContent        Start node to look for the element.  This should
3176    *                        not be an orphan node.
3177    * @return                If an element which matches aTagName, returns
3178    *                        an Element.  Otherwise, nullptr.
3179    */
3180   Element* GetInclusiveAncestorByTagNameInternal(const nsStaticAtom& aTagName,
3181                                                  nsIContent& aContent) const;
3182 
3183   /**
3184    * GetSelectedElement() returns a "selected" element node.  "selected" means:
3185    * - there is only one selection range
3186    * - the range starts from an element node or in an element
3187    * - the range ends at immediately after same element
3188    * - and the range does not include any other element nodes.
3189    * Additionally, only when aTagName is nsGkAtoms::href, this thinks that an
3190    * <a> element which has non-empty "href" attribute includes the range, the
3191    * <a> element is selected.
3192    *
3193    * NOTE: This method is implementation of nsIHTMLEditor.getSelectedElement()
3194    * and comm-central depends on this behavior.  Therefore, if you need to use
3195    * this method internally but you need to change, perhaps, you should create
3196    * another method for avoiding breakage of comm-central apps.
3197    *
3198    * @param aTagName    The atom of tag name in lower case.  Set this to
3199    *                    result  of EditorUtils::GetTagNameAtom() if you have a
3200    *                    tag name with nsString.
3201    *                    If nullptr, this returns any element node or nullptr.
3202    *                    If nsGkAtoms::href, this returns an <a> element which
3203    *                    has non-empty "href" attribute or nullptr.
3204    *                    If nsGkAtoms::anchor, this returns an <a> element which
3205    *                    has non-empty "name" attribute or nullptr.
3206    *                    Otherwise, returns an element node whose name is
3207    *                    same as aTagName or nullptr.
3208    * @param aRv         Returns error code.
3209    * @return            A "selected" element.
3210    */
3211   already_AddRefed<Element> GetSelectedElement(const nsAtom* aTagName,
3212                                                ErrorResult& aRv);
3213 
3214   /**
3215    * GetFirstTableRowElement() returns the first <tr> element in the most
3216    * nearest ancestor of aTableOrElementInTable or itself.
3217    *
3218    * @param aTableOrElementInTable      <table> element or another element.
3219    *                                    If this is a <table> element, returns
3220    *                                    first <tr> element in it.  Otherwise,
3221    *                                    returns first <tr> element in nearest
3222    *                                    ancestor <table> element.
3223    * @param aRv                         Returns an error code.  When
3224    *                                    aTableOrElementInTable is neither
3225    *                                    <table> nor in a <table> element,
3226    *                                    returns NS_ERROR_FAILURE.
3227    *                                    However, if <table> does not have
3228    *                                    <tr> element, returns NS_OK.
3229    */
3230   Element* GetFirstTableRowElement(Element& aTableOrElementInTable,
3231                                    ErrorResult& aRv) const;
3232 
3233   /**
3234    * GetNextTableRowElement() returns next <tr> element of aTableRowElement.
3235    * This won't cross <table> element boundary but may cross table section
3236    * elements like <tbody>.
3237    *
3238    * @param aTableRowElement    A <tr> element.
3239    * @param aRv                 Returns error.  If given element is <tr> but
3240    *                            there is no next <tr> element, this returns
3241    *                            nullptr but does not return error.
3242    */
3243   Element* GetNextTableRowElement(Element& aTableRowElement,
3244                                   ErrorResult& aRv) const;
3245 
3246   struct CellAndIndexes;
3247   struct CellData;
3248 
3249   /**
3250    * CellIndexes store both row index and column index of a table cell.
3251    */
3252   struct MOZ_STACK_CLASS CellIndexes final {
3253     int32_t mRow;
3254     int32_t mColumn;
3255 
3256     /**
3257      * This constructor initializes mRowIndex and mColumnIndex with indexes of
3258      * aCellElement.
3259      *
3260      * @param aCellElement      An <td> or <th> element.
3261      * @param aRv               Returns error if layout information is not
3262      *                          available or given element is not a table cell.
3263      */
CellIndexesfinal3264     MOZ_CAN_RUN_SCRIPT CellIndexes(Element& aCellElement, PresShell* aPresShell,
3265                                    ErrorResult& aRv)
3266         : mRow(-1), mColumn(-1) {
3267       MOZ_ASSERT(!aRv.Failed());
3268       Update(aCellElement, aPresShell, aRv);
3269     }
3270 
3271     /**
3272      * Update mRowIndex and mColumnIndex with indexes of aCellElement.
3273      *
3274      * @param                   See above.
3275      */
3276     MOZ_CAN_RUN_SCRIPT void Update(Element& aCellElement, PresShell* aPresShell,
3277                                    ErrorResult& aRv);
3278 
3279     /**
3280      * This constructor initializes mRowIndex and mColumnIndex with indexes of
3281      * cell element which contains anchor of Selection.
3282      *
3283      * @param aHTMLEditor       The editor which creates the instance.
3284      * @param aSelection        The Selection for the editor.
3285      * @param aRv               Returns error if there is no cell element
3286      *                          which contains anchor of Selection, or layout
3287      *                          information is not available.
3288      */
CellIndexesfinal3289     MOZ_CAN_RUN_SCRIPT CellIndexes(HTMLEditor& aHTMLEditor,
3290                                    Selection& aSelection, ErrorResult& aRv)
3291         : mRow(-1), mColumn(-1) {
3292       Update(aHTMLEditor, aSelection, aRv);
3293     }
3294 
3295     /**
3296      * Update mRowIndex and mColumnIndex with indexes of cell element which
3297      * contains anchor of Selection.
3298      *
3299      * @param                   See above.
3300      */
3301     MOZ_CAN_RUN_SCRIPT void Update(HTMLEditor& aHTMLEditor,
3302                                    Selection& aSelection, ErrorResult& aRv);
3303 
3304     bool operator==(const CellIndexes& aOther) const {
3305       return mRow == aOther.mRow && mColumn == aOther.mColumn;
3306     }
3307     bool operator!=(const CellIndexes& aOther) const {
3308       return mRow != aOther.mRow || mColumn != aOther.mColumn;
3309     }
3310 
3311    private:
CellIndexesfinal3312     CellIndexes() : mRow(-1), mColumn(-1) {}
3313 
3314     friend struct CellAndIndexes;
3315     friend struct CellData;
3316   };
3317 
3318   struct MOZ_STACK_CLASS CellAndIndexes final {
3319     RefPtr<Element> mElement;
3320     CellIndexes mIndexes;
3321 
3322     /**
3323      * This constructor initializes the members with cell element which is
3324      * selected by first range of the Selection.  Note that even if the
3325      * first range is in the cell element, this does not treat it as the
3326      * cell element is selected.
3327      */
CellAndIndexesfinal3328     MOZ_CAN_RUN_SCRIPT CellAndIndexes(HTMLEditor& aHTMLEditor,
3329                                       Selection& aSelection, ErrorResult& aRv) {
3330       Update(aHTMLEditor, aSelection, aRv);
3331     }
3332 
3333     /**
3334      * Update mElement and mIndexes with cell element which is selected by
3335      * first range of the Selection.  Note that even if the first range is
3336      * in the cell element, this does not treat it as the cell element is
3337      * selected.
3338      */
3339     MOZ_CAN_RUN_SCRIPT void Update(HTMLEditor& aHTMLEditor,
3340                                    Selection& aSelection, ErrorResult& aRv);
3341   };
3342 
3343   struct MOZ_STACK_CLASS CellData final {
3344     RefPtr<Element> mElement;
3345     // Current indexes which this is initialized with.
3346     CellIndexes mCurrent;
3347     // First column/row indexes of the cell.  When current position is spanned
3348     // from other column/row, this value becomes different from mCurrent.
3349     CellIndexes mFirst;
3350     // Computed rowspan/colspan values which are specified to the cell.
3351     // Note that if the cell has larger rowspan/colspan value than actual
3352     // table size, these values are the larger values.
3353     int32_t mRowSpan;
3354     int32_t mColSpan;
3355     // Effective rowspan/colspan value at the index.  For example, if first
3356     // cell element in first row has rowspan="3", then, if this is initialized
3357     // with 0-0 indexes, effective rowspan is 3.  However, if this is
3358     // initialized with 1-0 indexes, effective rowspan is 2.
3359     int32_t mEffectiveRowSpan;
3360     int32_t mEffectiveColSpan;
3361     // mIsSelected is set to true if mElement itself or its parent <tr> or
3362     // <table> is selected.  Otherwise, e.g., the cell just contains selection
3363     // range, this is set to false.
3364     bool mIsSelected;
3365 
CellDatafinal3366     CellData()
3367         : mRowSpan(-1),
3368           mColSpan(-1),
3369           mEffectiveRowSpan(-1),
3370           mEffectiveColSpan(-1),
3371           mIsSelected(false) {}
3372 
3373     /**
3374      * Those constructors initializes the members with a <table> element and
3375      * both row and column index to specify a cell element.
3376      */
CellDatafinal3377     CellData(HTMLEditor& aHTMLEditor, Element& aTableElement, int32_t aRowIndex,
3378              int32_t aColumnIndex, ErrorResult& aRv) {
3379       Update(aHTMLEditor, aTableElement, aRowIndex, aColumnIndex, aRv);
3380     }
3381 
CellDatafinal3382     CellData(HTMLEditor& aHTMLEditor, Element& aTableElement,
3383              const CellIndexes& aIndexes, ErrorResult& aRv) {
3384       Update(aHTMLEditor, aTableElement, aIndexes, aRv);
3385     }
3386 
3387     /**
3388      * Those Update() methods updates the members with a <table> element and
3389      * both row and column index to specify a cell element.
3390      */
Updatefinal3391     void Update(HTMLEditor& aHTMLEditor, Element& aTableElement,
3392                 int32_t aRowIndex, int32_t aColumnIndex, ErrorResult& aRv) {
3393       mCurrent.mRow = aRowIndex;
3394       mCurrent.mColumn = aColumnIndex;
3395       Update(aHTMLEditor, aTableElement, aRv);
3396     }
3397 
Updatefinal3398     void Update(HTMLEditor& aHTMLEditor, Element& aTableElement,
3399                 const CellIndexes& aIndexes, ErrorResult& aRv) {
3400       mCurrent = aIndexes;
3401       Update(aHTMLEditor, aTableElement, aRv);
3402     }
3403 
3404     void Update(HTMLEditor& aHTMLEditor, Element& aTableElement,
3405                 ErrorResult& aRv);
3406 
3407     /**
3408      * FailedOrNotFound() returns true if this failed to initialize/update
3409      * or succeeded but found no cell element.
3410      */
FailedOrNotFoundfinal3411     bool FailedOrNotFound() const { return !mElement; }
3412 
3413     /**
3414      * IsSpannedFromOtherRowOrColumn(), IsSpannedFromOtherColumn and
3415      * IsSpannedFromOtherRow() return true if there is no cell element
3416      * at the index because of spanning from other row and/or column.
3417      */
IsSpannedFromOtherRowOrColumnfinal3418     bool IsSpannedFromOtherRowOrColumn() const {
3419       return mElement && mCurrent != mFirst;
3420     }
IsSpannedFromOtherColumnfinal3421     bool IsSpannedFromOtherColumn() const {
3422       return mElement && mCurrent.mColumn != mFirst.mColumn;
3423     }
IsSpannedFromOtherRowfinal3424     bool IsSpannedFromOtherRow() const {
3425       return mElement && mCurrent.mRow != mFirst.mRow;
3426     }
3427 
3428     /**
3429      * NextColumnIndex() and NextRowIndex() return column/row index of
3430      * next cell.  Note that this does not check whether there is next
3431      * cell or not actually.
3432      */
NextColumnIndexfinal3433     int32_t NextColumnIndex() const {
3434       if (NS_WARN_IF(FailedOrNotFound())) {
3435         return -1;
3436       }
3437       return mCurrent.mColumn + mEffectiveColSpan;
3438     }
NextRowIndexfinal3439     int32_t NextRowIndex() const {
3440       if (NS_WARN_IF(FailedOrNotFound())) {
3441         return -1;
3442       }
3443       return mCurrent.mRow + mEffectiveRowSpan;
3444     }
3445 
3446     /**
3447      * LastColumnIndex() and LastRowIndex() return column/row index of
3448      * column/row which is spanned by the cell.
3449      */
LastColumnIndexfinal3450     int32_t LastColumnIndex() const {
3451       if (NS_WARN_IF(FailedOrNotFound())) {
3452         return -1;
3453       }
3454       return NextColumnIndex() - 1;
3455     }
LastRowIndexfinal3456     int32_t LastRowIndex() const {
3457       if (NS_WARN_IF(FailedOrNotFound())) {
3458         return -1;
3459       }
3460       return NextRowIndex() - 1;
3461     }
3462 
3463     /**
3464      * NumberOfPrecedingColmuns() and NumberOfPrecedingRows() return number of
3465      * preceding columns/rows if current index is spanned from other column/row.
3466      * Otherwise, i.e., current point is not spanned form other column/row,
3467      * returns 0.
3468      */
NumberOfPrecedingColmunsfinal3469     int32_t NumberOfPrecedingColmuns() const {
3470       if (NS_WARN_IF(FailedOrNotFound())) {
3471         return -1;
3472       }
3473       return mCurrent.mColumn - mFirst.mColumn;
3474     }
NumberOfPrecedingRowsfinal3475     int32_t NumberOfPrecedingRows() const {
3476       if (NS_WARN_IF(FailedOrNotFound())) {
3477         return -1;
3478       }
3479       return mCurrent.mRow - mFirst.mRow;
3480     }
3481 
3482     /**
3483      * NumberOfFollowingColumns() and NumberOfFollowingRows() return
3484      * number of remaining columns/rows if the cell spans to other
3485      * column/row.
3486      */
NumberOfFollowingColumnsfinal3487     int32_t NumberOfFollowingColumns() const {
3488       if (NS_WARN_IF(FailedOrNotFound())) {
3489         return -1;
3490       }
3491       return mEffectiveColSpan - 1;
3492     }
NumberOfFollowingRowsfinal3493     int32_t NumberOfFollowingRows() const {
3494       if (NS_WARN_IF(FailedOrNotFound())) {
3495         return -1;
3496       }
3497       return mEffectiveRowSpan - 1;
3498     }
3499   };
3500 
3501   /**
3502    * TableSize stores and computes number of rows and columns of a <table>
3503    * element.
3504    */
3505   struct MOZ_STACK_CLASS TableSize final {
3506     int32_t mRowCount;
3507     int32_t mColumnCount;
3508 
3509     /**
3510      * @param aHTMLEditor               The editor which creates the instance.
3511      * @param aTableOrElementInTable    If a <table> element, computes number
3512      *                                  of rows and columns of it.
3513      *                                  If another element in a <table> element,
3514      *                                  computes number of rows and columns
3515      *                                  of nearest ancestor <table> element.
3516      *                                  Otherwise, i.e., non-<table> element
3517      *                                  not in <table>, returns error.
3518      * @param aRv                       Returns error if the element is not
3519      *                                  in <table> or layout information is
3520      *                                  not available.
3521      */
TableSizefinal3522     TableSize(HTMLEditor& aHTMLEditor, Element& aTableOrElementInTable,
3523               ErrorResult& aRv)
3524         : mRowCount(-1), mColumnCount(-1) {
3525       MOZ_ASSERT(!aRv.Failed());
3526       Update(aHTMLEditor, aTableOrElementInTable, aRv);
3527     }
3528 
3529     /**
3530      * Update mRowCount and mColumnCount for aTableOrElementInTable.
3531      * See above for the detail.
3532      */
3533     void Update(HTMLEditor& aHTMLEditor, Element& aTableOrElementInTable,
3534                 ErrorResult& aRv);
3535 
IsEmptyfinal3536     bool IsEmpty() const { return !mRowCount || !mColumnCount; }
3537   };
3538 
3539   /**
3540    * GetTableCellElementAt() returns a <td> or <th> element of aTableElement
3541    * if there is a cell at the indexes.
3542    *
3543    * @param aTableElement       Must be a <table> element.
3544    * @param aCellIndexes        Indexes of cell which you want.
3545    *                            If rowspan and/or colspan is specified 2 or
3546    *                            larger, any indexes are allowed to retrieve
3547    *                            the cell in the area.
3548    * @return                    The cell element if there is in the <table>.
3549    *                            Returns nullptr without error if the indexes
3550    *                            are out of bounds.
3551    */
GetTableCellElementAt(Element & aTableElement,const CellIndexes & aCellIndexes)3552   Element* GetTableCellElementAt(Element& aTableElement,
3553                                  const CellIndexes& aCellIndexes) const {
3554     return GetTableCellElementAt(aTableElement, aCellIndexes.mRow,
3555                                  aCellIndexes.mColumn);
3556   }
3557   Element* GetTableCellElementAt(Element& aTableElement, int32_t aRowIndex,
3558                                  int32_t aColumnIndex) const;
3559 
3560   /**
3561    * GetSelectedOrParentTableElement() returns <td>, <th>, <tr> or <table>
3562    * element:
3563    *   #1 if the first selection range selects a cell, returns it.
3564    *   #2 if the first selection range does not select a cell and
3565    *      the selection anchor refers a <table>, returns it.
3566    *   #3 if the first selection range does not select a cell and
3567    *      the selection anchor refers a <tr>, returns it.
3568    *   #4 if the first selection range does not select a cell and
3569    *      the selection anchor refers a <td>, returns it.
3570    *   #5 otherwise, nearest ancestor <td> or <th> element of the
3571    *      selection anchor if there is.
3572    * In #1 and #4, *aIsCellSelected will be set to true (i.e,, when
3573    * a selection range selects a cell element).
3574    */
3575   already_AddRefed<Element> GetSelectedOrParentTableElement(
3576       ErrorResult& aRv, bool* aIsCellSelected = nullptr) const;
3577 
3578   /**
3579    * PasteInternal() pasts text with replacing selected content.
3580    * This tries to dispatch ePaste event first.  If its defaultPrevent() is
3581    * called, this does nothing but returns NS_OK.
3582    *
3583    * @param aClipboardType      nsIClipboard::kGlobalClipboard or
3584    *                            nsIClipboard::kSelectionClipboard.
3585    */
3586   MOZ_CAN_RUN_SCRIPT nsresult PasteInternal(int32_t aClipboardType);
3587 
3588   /**
3589    * InsertWithQuotationsAsSubAction() inserts aQuotedText with appending ">"
3590    * to start of every line.
3591    *
3592    * @param aQuotedText         String to insert.  This will be quoted by ">"
3593    *                            automatically.
3594    */
3595   [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult
3596   InsertWithQuotationsAsSubAction(const nsAString& aQuotedText) final;
3597 
3598   /**
3599    * InsertAsCitedQuotationInternal() inserts a <blockquote> element whose
3600    * cite attribute is aCitation and whose content is aQuotedText.
3601    * Note that this shouldn't be called when IsPlaintextEditor() is true.
3602    *
3603    * @param aQuotedText     HTML source if aInsertHTML is true.  Otherwise,
3604    *                        plain text.  This is inserted into new <blockquote>
3605    *                        element.
3606    * @param aCitation       cite attribute value of new <blockquote> element.
3607    * @param aInsertHTML     true if aQuotedText should be treated as HTML
3608    *                        source.
3609    *                        false if aQuotedText should be treated as plain
3610    *                        text.
3611    * @param aNodeInserted   [OUT] The new <blockquote> element.
3612    */
3613   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertAsCitedQuotationInternal(
3614       const nsAString& aQuotedText, const nsAString& aCitation,
3615       bool aInsertHTML, nsINode** aNodeInserted);
3616 
3617   /**
3618    * InsertNodeIntoProperAncestorWithTransaction() attempts to insert aNode
3619    * into the document, at aPointToInsert.  Checks with strict dtd to see if
3620    * containment is allowed.  If not allowed, will attempt to find a parent
3621    * in the parent hierarchy of aPointToInsert.GetContainer() that will accept
3622    * aNode as a child.  If such a parent is found, will split the document
3623    * tree from aPointToInsert up to parent, and then insert aNode.
3624    * aPointToInsert is then adjusted to point to the actual location that
3625    * aNode was inserted at.  aSplitAtEdges specifies if the splitting process
3626    * is allowed to result in empty nodes.
3627    *
3628    * @param aNode             Node to insert.
3629    * @param aPointToInsert    Insertion point.
3630    * @param aSplitAtEdges     Splitting can result in empty nodes?
3631    * @return                  Returns inserted point if succeeded.
3632    *                          Otherwise, the result is not set.
3633    */
3634   MOZ_CAN_RUN_SCRIPT EditorDOMPoint InsertNodeIntoProperAncestorWithTransaction(
3635       nsIContent& aNode, const EditorDOMPoint& aPointToInsert,
3636       SplitAtEdges aSplitAtEdges);
3637 
3638   /**
3639    * InsertBRElementAtSelectionWithTransaction() inserts a new <br> element at
3640    * selection.  If there is non-collapsed selection ranges, the selected
3641    * ranges is deleted first.
3642    */
3643   MOZ_CAN_RUN_SCRIPT nsresult InsertBRElementAtSelectionWithTransaction();
3644 
3645   /**
3646    * InsertTextWithQuotationsInternal() replaces selection with new content.
3647    * First, this method splits aStringToInsert to multiple chunks which start
3648    * with non-linebreaker except first chunk and end with a linebreaker except
3649    * last chunk.  Then, each chunk starting with ">" is inserted after wrapping
3650    * with <span _moz_quote="true">, and each chunk not starting with ">" is
3651    * inserted as normal text.
3652    */
3653   MOZ_CAN_RUN_SCRIPT nsresult
3654   InsertTextWithQuotationsInternal(const nsAString& aStringToInsert);
3655 
3656   /**
3657    * ReplaceContainerWithTransactionInternal() is implementation of
3658    * ReplaceContainerWithTransaction() and
3659    * ReplaceContainerAndCloneAttributesWithTransaction().
3660    *
3661    * @param aOldContainer       The element which will be replaced with new
3662    *                            element.
3663    * @param aTagName            The name of new element node.
3664    * @param aAttribute          Attribute name which will be set to the new
3665    *                            element.  This will be ignored if
3666    *                            aCloneAllAttributes is set to true.
3667    * @param aAttributeValue     Attribute value which will be set to
3668    *                            aAttribute.
3669    * @param aCloneAllAttributes If true, all attributes of aOldContainer will
3670    *                            be copied to the new element.
3671    */
3672   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element>
3673   ReplaceContainerWithTransactionInternal(Element& aElement, nsAtom& aTagName,
3674                                           nsAtom& aAttribute,
3675                                           const nsAString& aAttributeValue,
3676                                           bool aCloneAllAttributes);
3677 
3678   /**
3679    * InsertContainerWithTransactionInternal() creates new element whose name is
3680    * aTagName, moves aContent into the new element, then, inserts the new
3681    * element into where aContent was.  If aAttribute is not nsGkAtoms::_empty,
3682    * aAttribute of the new element will be set to aAttributeValue.
3683    *
3684    * @param aContent            The content which will be wrapped with new
3685    *                            element.
3686    * @param aTagName            Element name of new element which will wrap
3687    *                            aContent and be inserted into where aContent
3688    *                            was.
3689    * @param aAttribute          Attribute which should be set to the new
3690    *                            element.  If this is nsGkAtoms::_empty,
3691    *                            this does not set any attributes to the new
3692    *                            element.
3693    * @param aAttributeValue     Value to be set to aAttribute.
3694    * @return                    The new element.
3695    */
3696   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element>
3697   InsertContainerWithTransactionInternal(nsIContent& aContent, nsAtom& aTagName,
3698                                          nsAtom& aAttribute,
3699                                          const nsAString& aAttributeValue);
3700 
3701   /**
3702    * DeleteSelectionAndCreateElement() creates a element whose name is aTag.
3703    * And insert it into the DOM tree after removing the selected content.
3704    *
3705    * @param aTag                The element name to be created.
3706    * @return                    Created new element.
3707    */
3708   MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> DeleteSelectionAndCreateElement(
3709       nsAtom& aTag);
3710 
3711   /**
3712    * This method first deletes the selection, if it's not collapsed.  Then if
3713    * the selection lies in a CharacterData node, it splits it.  If the
3714    * selection is at this point collapsed in a CharacterData node, it's
3715    * adjusted to be collapsed right before or after the node instead (which is
3716    * always possible, since the node was split).
3717    */
3718   MOZ_CAN_RUN_SCRIPT nsresult DeleteSelectionAndPrepareToCreateNode();
3719 
3720   /**
3721    * PrepareToInsertBRElement() returns a point where new <br> element should
3722    * be inserted.  If aPointToInsert points middle of a text node, this method
3723    * splits the text node and returns the point before right node.
3724    *
3725    * @param aPointToInsert      Candidate point to insert new <br> element.
3726    * @return                    Computed point to insert new <br> element.
3727    *                            If something failed, this is unset.
3728    */
3729   MOZ_CAN_RUN_SCRIPT EditorDOMPoint
3730   PrepareToInsertBRElement(const EditorDOMPoint& aPointToInsert);
3731 
3732   /**
3733    * IndentAsSubAction() indents the content around Selection.
3734    */
3735   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult IndentAsSubAction();
3736 
3737   /**
3738    * OutdentAsSubAction() outdents the content around Selection.
3739    */
3740   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult OutdentAsSubAction();
3741 
3742   MOZ_CAN_RUN_SCRIPT nsresult LoadHTML(const nsAString& aInputString);
3743 
3744   /**
3745    * SetInlinePropertyInternal() stores new style with `mTypeInState` if
3746    * `Selection` is collapsed.  Otherwise, applying the style at all selection
3747    * ranges.
3748    *
3749    * @param aProperty           One of the presentation tag names which we
3750    *                            support in style editor.
3751    * @param aAttribute          For some aProperty values, needs to be set to
3752    *                            its attribute name.  Otherwise, nullptr.
3753    * @param aAttributeValue     The value of aAttribute.
3754    */
3755   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertyInternal(
3756       nsAtom& aProperty, nsAtom* aAttribute, const nsAString& aValue);
3757 
3758   /**
3759    * RemoveInlinePropertyInternal() removes specified style from `mTypeInState`
3760    * if `Selection` is collapsed.  Otherwise, removing the style.
3761    *
3762    * @param aHTMLProperty       nullptr if you want to remove all inline styles.
3763    *                            Otherwise, one of the presentation tag names
3764    *                            which we support in style editor.
3765    * @param aAttribute          For some aHTMLProperty values, need to be set to
3766    *                            its attribute name.  Otherwise, nullptr.
3767    * @param aRemoveRelatedElements      If Yes, this method removes different
3768    *                                    name's elements in the block if
3769    *                                    necessary.  For example, if
3770    *                                    aHTMLProperty is nsGkAtoms::b,
3771    *                                    `<strong>` elements are also removed.
3772    */
3773   enum class RemoveRelatedElements { Yes, No };
3774   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveInlinePropertyInternal(
3775       nsStaticAtom* aHTMLProperty, nsStaticAtom* aAttribute,
3776       RemoveRelatedElements aRemoveRelatedElements);
3777 
3778   /**
3779    * ReplaceHeadContentsWithSourceWithTransaction() replaces all children of
3780    * <head> element with given source code.  This is undoable.
3781    *
3782    * @param aSourceToInsert     HTML source fragment to replace the children
3783    *                            of <head> element.
3784    */
3785   MOZ_CAN_RUN_SCRIPT nsresult ReplaceHeadContentsWithSourceWithTransaction(
3786       const nsAString& aSourceToInsert);
3787 
3788   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetCSSBackgroundColorState(
3789       bool* aMixed, nsAString& aOutColor, bool aBlockLevel);
3790   nsresult GetHTMLBackgroundColorState(bool* aMixed, nsAString& outColor);
3791 
3792   nsresult GetLastCellInRow(nsINode* aRowNode, nsINode** aCellNode);
3793 
3794   /**
3795    * This sets background on the appropriate container element (table, cell,)
3796    * or calls into nsTextEditor to set the page background.
3797    */
3798   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3799   SetCSSBackgroundColorWithTransaction(const nsAString& aColor);
3800   MOZ_CAN_RUN_SCRIPT nsresult
3801   SetHTMLBackgroundColorWithTransaction(const nsAString& aColor);
3802 
3803   MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void InitializeSelectionAncestorLimit(
3804       nsIContent& aAncestorLimit) override;
3805 
3806   /**
3807    * Make the given selection span the entire document.
3808    */
3809   [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult SelectEntireDocument()
3810       override;
3811 
3812   /**
3813    * Use this to assure that selection is set after attribute nodes when
3814    * trying to collapse selection at begining of a block node
3815    * e.g., when setting at beginning of a table cell
3816    * This will stop at a table, however, since we don't want to
3817    * "drill down" into nested tables.
3818    */
3819   MOZ_CAN_RUN_SCRIPT void CollapseSelectionToDeepestNonTableFirstChild(
3820       nsINode* aNode);
3821   /**
3822    * MaybeCollapseSelectionAtFirstEditableNode() may collapse selection at
3823    * proper position to staring to edit.  If there is a non-editable node
3824    * before any editable text nodes or inline elements which can have text
3825    * nodes as their children, collapse selection at start of the editing
3826    * host.  If there is an editable text node which is not collapsed, collapses
3827    * selection at the start of the text node.  If there is an editable inline
3828    * element which cannot have text nodes as its child, collapses selection at
3829    * before the element node.  Otherwise, collapses selection at start of the
3830    * editing host.
3831    *
3832    * @param aIgnoreIfSelectionInEditingHost
3833    *                        This method does nothing if selection is in the
3834    *                        editing host except if it's collapsed at start of
3835    *                        the editing host.
3836    *                        Note that if selection ranges were outside of
3837    *                        current selection limiter, selection was collapsed
3838    *                        at the start of the editing host therefore, if
3839    *                        you call this with setting this to true, you can
3840    *                        keep selection ranges if user has already been
3841    *                        changed.
3842    */
3843   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3844   MaybeCollapseSelectionAtFirstEditableNode(
3845       bool aIgnoreIfSelectionInEditingHost);
3846 
3847   class BlobReader final {
3848     typedef EditorBase::AutoEditActionDataSetter AutoEditActionDataSetter;
3849 
3850    public:
3851     BlobReader(dom::BlobImpl* aBlob, HTMLEditor* aHTMLEditor, bool aIsSafe,
3852                Document* aSourceDoc, const EditorDOMPoint& aPointToInsert,
3853                bool aDoDeleteSelection);
3854 
3855     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BlobReader)
3856     NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(BlobReader)
3857 
3858     MOZ_CAN_RUN_SCRIPT nsresult OnResult(const nsACString& aResult);
3859     nsresult OnError(const nsAString& aErrorName);
3860 
3861    private:
3862     ~BlobReader() = default;
3863 
3864     RefPtr<dom::BlobImpl> mBlob;
3865     RefPtr<HTMLEditor> mHTMLEditor;
3866     RefPtr<dom::DataTransfer> mDataTransfer;
3867     nsCOMPtr<Document> mSourceDoc;
3868     EditorDOMPoint mPointToInsert;
3869     EditAction mEditAction;
3870     bool mIsSafe;
3871     bool mDoDeleteSelection;
3872     bool mNeedsToDispatchBeforeInputEvent;
3873   };
3874 
3875   virtual void CreateEventListeners() override;
3876   virtual nsresult InstallEventListeners() override;
3877   virtual void RemoveEventListeners() override;
3878 
3879   bool ShouldReplaceRootElement() const;
3880   MOZ_CAN_RUN_SCRIPT void NotifyRootChanged();
3881   Element* GetBodyElement() const;
3882 
3883   /**
3884    * Get the focused node of this editor.
3885    * @return    If the editor has focus, this returns the focused node.
3886    *            Otherwise, returns null.
3887    */
3888   nsINode* GetFocusedNode() const;
3889 
3890   virtual already_AddRefed<Element> GetInputEventTargetElement() const override;
3891 
3892   /**
3893    * Return TRUE if aElement is a table-related elemet and caret was set.
3894    */
3895   MOZ_CAN_RUN_SCRIPT bool SetCaretInTableCell(dom::Element* aElement);
3896 
3897   /**
3898    * HandleTabKeyPressInTable() handles "Tab" key press in table if selection
3899    * is in a `<table>` element.
3900    */
3901   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
3902   HandleTabKeyPressInTable(WidgetKeyboardEvent* aKeyboardEvent);
3903 
3904   /**
3905    * InsertPosition is an enum to indicate where the method should insert to.
3906    */
3907   enum class InsertPosition {
3908     // Before selected cell or a cell containing first selection range.
3909     eBeforeSelectedCell,
3910     // After selected cell or a cell containing first selection range.
3911     eAfterSelectedCell,
3912   };
3913 
3914   /**
3915    * InsertTableCellsWithTransaction() inserts <td> elements before or after
3916    * a cell element containing first selection range.  I.e., if the cell
3917    * spans columns and aInsertPosition is eAfterSelectedCell, new columns
3918    * will be inserted after the right-most column which contains the cell.
3919    * Note that this simply inserts <td> elements, i.e., colspan and rowspan
3920    * around the cell containing selection are not modified.  So, for example,
3921    * adding a cell to rectangular table changes non-rectangular table.
3922    * And if the cell containing selection is at left of row-spanning cell,
3923    * it may be moved to right side of the row-spanning cell after inserting
3924    * some cell elements before it.  Similarly, colspan won't be adjusted
3925    * for keeping table rectangle.
3926    * If first selection range is not in table cell element, this does nothing
3927    * but does not return error.
3928    *
3929    * @param aNumberOfCellssToInsert     Number of cells to insert.
3930    * @param aInsertPosition             Before or after the target cell which
3931    *                                    contains first selection range.
3932    */
3933   MOZ_CAN_RUN_SCRIPT nsresult InsertTableCellsWithTransaction(
3934       int32_t aNumberOfCellsToInsert, InsertPosition aInsertPosition);
3935 
3936   /**
3937    * InsertTableColumnsWithTransaction() inserts columns before or after
3938    * a cell element containing first selection range.  I.e., if the cell
3939    * spans columns and aInsertPosition is eAfterSelectedCell, new columns
3940    * will be inserted after the right-most row which contains the cell.
3941    * If first selection range is not in table cell element, this does nothing
3942    * but does not return error.
3943    *
3944    * @param aNumberOfColumnsToInsert    Number of columns to insert.
3945    * @param aInsertPosition             Before or after the target cell which
3946    *                                    contains first selection range.
3947    */
3948   MOZ_CAN_RUN_SCRIPT nsresult InsertTableColumnsWithTransaction(
3949       int32_t aNumberOfColumnsToInsert, InsertPosition aInsertPosition);
3950 
3951   /**
3952    * InsertTableRowsWithTransaction() inserts <tr> elements before or after
3953    * a cell element containing first selection range.  I.e., if the cell
3954    * spans rows and aInsertPosition is eAfterSelectedCell, new rows will be
3955    * inserted after the most-bottom row which contains the cell.  If first
3956    * selection range is not in table cell element, this does nothing but
3957    * does not return error.
3958    *
3959    * @param aNumberOfRowsToInsert       Number of rows to insert.
3960    * @param aInsertPosition             Before or after the target cell which
3961    *                                    contains first selection range.
3962    */
3963   MOZ_CAN_RUN_SCRIPT nsresult InsertTableRowsWithTransaction(
3964       int32_t aNumberOfRowsToInsert, InsertPosition aInsertPosition);
3965 
3966   /**
3967    * Insert a new cell after or before supplied aCell.
3968    * Optional: If aNewCell supplied, returns the newly-created cell (addref'd,
3969    * of course)
3970    * This doesn't change or use the current selection.
3971    */
3972   MOZ_CAN_RUN_SCRIPT nsresult InsertCell(Element* aCell, int32_t aRowSpan,
3973                                          int32_t aColSpan, bool aAfter,
3974                                          bool aIsHeader, Element** aNewCell);
3975 
3976   /**
3977    * DeleteSelectedTableColumnsWithTransaction() removes cell elements which
3978    * belong to same columns of selected cell elements.
3979    * If only one cell element is selected or first selection range is
3980    * in a cell, removes cell elements which belong to same column.
3981    * If 2 or more cell elements are selected, removes cell elements which
3982    * belong to any of all selected columns.  In this case,
3983    * aNumberOfColumnsToDelete is ignored.
3984    * If there is no selection ranges, returns error.
3985    * If selection is not in a cell element, this does not return error,
3986    * just does nothing.
3987    * WARNING: This does not remove <col> nor <colgroup> elements.
3988    *
3989    * @param aNumberOfColumnsToDelete    Number of columns to remove.  This is
3990    *                                    ignored if 2 ore more cells are
3991    *                                    selected.
3992    */
3993   MOZ_CAN_RUN_SCRIPT nsresult
3994   DeleteSelectedTableColumnsWithTransaction(int32_t aNumberOfColumnsToDelete);
3995 
3996   /**
3997    * DeleteTableColumnWithTransaction() removes cell elements which belong
3998    * to the specified column.
3999    * This method adjusts colspan attribute value if cells spanning the
4000    * column to delete.
4001    * WARNING: This does not remove <col> nor <colgroup> elements.
4002    *
4003    * @param aTableElement       The <table> element which contains the
4004    *                            column which you want to remove.
4005    * @param aRowIndex           Index of the column which you want to remove.
4006    *                            0 is the first column.
4007    */
4008   MOZ_CAN_RUN_SCRIPT nsresult DeleteTableColumnWithTransaction(
4009       Element& aTableElement, int32_t aColumnIndex);
4010 
4011   /**
4012    * DeleteSelectedTableRowsWithTransaction() removes <tr> elements.
4013    * If only one cell element is selected or first selection range is
4014    * in a cell, removes <tr> elements starting from a <tr> element
4015    * containing the selected cell or first selection range.
4016    * If 2 or more cell elements are selected, all <tr> elements
4017    * which contains selected cell(s).  In this case, aNumberOfRowsToDelete
4018    * is ignored.
4019    * If there is no selection ranges, returns error.
4020    * If selection is not in a cell element, this does not return error,
4021    * just does nothing.
4022    *
4023    * @param aNumberOfRowsToDelete   Number of rows to remove.  This is ignored
4024    *                                if 2 or more cells are selected.
4025    */
4026   MOZ_CAN_RUN_SCRIPT nsresult
4027   DeleteSelectedTableRowsWithTransaction(int32_t aNumberOfRowsToDelete);
4028 
4029   /**
4030    * DeleteTableRowWithTransaction() removes a <tr> element whose index in
4031    * the <table> is aRowIndex.
4032    * This method adjusts rowspan attribute value if the <tr> element contains
4033    * cells which spans rows.
4034    *
4035    * @param aTableElement       The <table> element which contains the
4036    *                            <tr> element which you want to remove.
4037    * @param aRowIndex           Index of the <tr> element which you want to
4038    *                            remove.  0 is the first row.
4039    */
4040   MOZ_CAN_RUN_SCRIPT nsresult
4041   DeleteTableRowWithTransaction(Element& aTableElement, int32_t aRowIndex);
4042 
4043   /**
4044    * DeleteTableCellWithTransaction() removes table cell elements.  If two or
4045    * more cell elements are selected, this removes all selected cell elements.
4046    * Otherwise, this removes some cell elements starting from selected cell
4047    * element or a cell containing first selection range.  When this removes
4048    * last cell element in <tr> or <table>, this removes the <tr> or the
4049    * <table> too.  Note that when removing a cell causes number of its row
4050    * becomes less than the others, this method does NOT fill the place with
4051    * rowspan nor colspan.  This does not return error even if selection is not
4052    * in cell element, just does nothing.
4053    *
4054    * @param aNumberOfCellsToDelete  Number of cells to remove.  This is ignored
4055    *                                if 2 or more cells are selected.
4056    */
4057   MOZ_CAN_RUN_SCRIPT nsresult
4058   DeleteTableCellWithTransaction(int32_t aNumberOfCellsToDelete);
4059 
4060   /**
4061    * DeleteAllChildrenWithTransaction() removes all children of aElement from
4062    * the tree.
4063    *
4064    * @param aElement        The element whose children you want to remove.
4065    */
4066   MOZ_CAN_RUN_SCRIPT nsresult
4067   DeleteAllChildrenWithTransaction(Element& aElement);
4068 
4069   /**
4070    * Move all contents from aCellToMerge into aTargetCell (append at end).
4071    */
4072   MOZ_CAN_RUN_SCRIPT nsresult MergeCells(RefPtr<Element> aTargetCell,
4073                                          RefPtr<Element> aCellToMerge,
4074                                          bool aDeleteCellToMerge);
4075 
4076   /**
4077    * DeleteTableElementAndChildren() removes aTableElement (and its children)
4078    * from the DOM tree with transaction.
4079    *
4080    * @param aTableElement   The <table> element which you want to remove.
4081    */
4082   MOZ_CAN_RUN_SCRIPT nsresult
4083   DeleteTableElementAndChildrenWithTransaction(Element& aTableElement);
4084 
4085   MOZ_CAN_RUN_SCRIPT nsresult SetColSpan(Element* aCell, int32_t aColSpan);
4086   MOZ_CAN_RUN_SCRIPT nsresult SetRowSpan(Element* aCell, int32_t aRowSpan);
4087 
4088   /**
4089    * Helper used to get nsTableWrapperFrame for a table.
4090    */
4091   static nsTableWrapperFrame* GetTableFrame(Element* aTable);
4092 
4093   /**
4094    * GetNumberOfCellsInRow() returns number of actual cell elements in the row.
4095    * If some cells appear by "rowspan" in other rows, they are ignored.
4096    *
4097    * @param aTableElement   The <table> element.
4098    * @param aRowIndex       Valid row index in aTableElement.  This method
4099    *                        counts cell elements in the row.
4100    * @return                -1 if this meets unexpected error.
4101    *                        Otherwise, number of cells which this method found.
4102    */
4103   int32_t GetNumberOfCellsInRow(Element& aTableElement, int32_t aRowIndex);
4104 
4105   /**
4106    * Test if all cells in row or column at given index are selected.
4107    */
4108   bool AllCellsInRowSelected(Element* aTable, int32_t aRowIndex,
4109                              int32_t aNumberOfColumns);
4110   bool AllCellsInColumnSelected(Element* aTable, int32_t aColIndex,
4111                                 int32_t aNumberOfRows);
4112 
4113   bool IsEmptyCell(Element* aCell);
4114 
4115   /**
4116    * Most insert methods need to get the same basic context data.
4117    * Any of the pointers may be null if you don't need that datum (for more
4118    * efficiency).
4119    * Input: *aCell is a known cell,
4120    *        if null, cell is obtained from the anchor node of the selection.
4121    * Returns NS_EDITOR_ELEMENT_NOT_FOUND if cell is not found even if aCell is
4122    * null.
4123    */
4124   MOZ_CAN_RUN_SCRIPT nsresult GetCellContext(Element** aTable, Element** aCell,
4125                                              nsINode** aCellParent,
4126                                              int32_t* aCellOffset,
4127                                              int32_t* aRowIndex,
4128                                              int32_t* aColIndex);
4129 
4130   nsresult GetCellSpansAt(Element* aTable, int32_t aRowIndex, int32_t aColIndex,
4131                           int32_t& aActualRowSpan, int32_t& aActualColSpan);
4132 
4133   MOZ_CAN_RUN_SCRIPT nsresult SplitCellIntoColumns(
4134       Element* aTable, int32_t aRowIndex, int32_t aColIndex,
4135       int32_t aColSpanLeft, int32_t aColSpanRight, Element** aNewCell);
4136 
4137   MOZ_CAN_RUN_SCRIPT nsresult SplitCellIntoRows(
4138       Element* aTable, int32_t aRowIndex, int32_t aColIndex,
4139       int32_t aRowSpanAbove, int32_t aRowSpanBelow, Element** aNewCell);
4140 
4141   MOZ_CAN_RUN_SCRIPT nsresult CopyCellBackgroundColor(Element* aDestCell,
4142                                                       Element* aSourceCell);
4143 
4144   /**
4145    * Reduce rowspan/colspan when cells span into nonexistent rows/columns.
4146    */
4147   MOZ_CAN_RUN_SCRIPT nsresult FixBadRowSpan(Element* aTable, int32_t aRowIndex,
4148                                             int32_t& aNewRowCount);
4149   MOZ_CAN_RUN_SCRIPT nsresult FixBadColSpan(Element* aTable, int32_t aColIndex,
4150                                             int32_t& aNewColCount);
4151 
4152   /**
4153    * XXX NormalizeTableInternal() is broken.  If it meets a cell which has
4154    *     bigger or smaller rowspan or colspan than actual number of cells,
4155    *     this always failed to scan the table.  Therefore, this does nothing
4156    *     when the table should be normalized.
4157    *
4158    * @param aTableOrElementInTable  An element which is in a <table> element
4159    *                                or <table> element itself.  Otherwise,
4160    *                                this returns NS_OK but does nothing.
4161    */
4162   MOZ_CAN_RUN_SCRIPT nsresult
4163   NormalizeTableInternal(Element& aTableOrElementInTable);
4164 
4165   /**
4166    * Fallback method: Call this after using ClearSelection() and you
4167    * failed to set selection to some other content in the document.
4168    */
4169   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetSelectionAtDocumentStart();
4170 
4171   // Methods for handling plaintext quotations
4172   MOZ_CAN_RUN_SCRIPT nsresult PasteAsPlaintextQuotation(int32_t aSelectionType);
4173 
4174   /**
4175    * Insert a string as quoted text, replacing the selected text (if any).
4176    * @param aQuotedText     The string to insert.
4177    * @param aAddCites       Whether to prepend extra ">" to each line
4178    *                        (usually true, unless those characters
4179    *                        have already been added.)
4180    * @return aNodeInserted  The node spanning the insertion, if applicable.
4181    *                        If aAddCites is false, this will be null.
4182    */
4183   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertAsPlaintextQuotation(
4184       const nsAString& aQuotedText, bool aAddCites, nsINode** aNodeInserted);
4185 
4186   /**
4187    * InsertObject() inserts given object at aPointToInsert.
4188    */
4189   MOZ_CAN_RUN_SCRIPT nsresult InsertObject(const nsACString& aType,
4190                                            nsISupports* aObject, bool aIsSafe,
4191                                            Document* aSourceDoc,
4192                                            const EditorDOMPoint& aPointToInsert,
4193                                            bool aDoDeleteSelection);
4194 
4195   // factored methods for handling insertion of data from transferables
4196   // (drag&drop or clipboard)
4197   virtual nsresult PrepareTransferable(
4198       nsITransferable** aTransferable) override;
4199   nsresult PrepareHTMLTransferable(nsITransferable** aTransferable);
4200   MOZ_CAN_RUN_SCRIPT nsresult InsertFromTransferable(
4201       nsITransferable* aTransferable, Document* aSourceDoc,
4202       const nsAString& aContextStr, const nsAString& aInfoStr,
4203       bool aHavePrivateHTMLFlavor, bool aDoDeleteSelection);
4204 
4205   /**
4206    * InsertFromDataTransfer() is called only when user drops data into
4207    * this editor.  Don't use this method for other purposes.
4208    */
4209   MOZ_CAN_RUN_SCRIPT nsresult InsertFromDataTransfer(
4210       dom::DataTransfer* aDataTransfer, int32_t aIndex, Document* aSourceDoc,
4211       const EditorDOMPoint& aDroppedAt, bool aDoDeleteSelection);
4212 
4213   bool HavePrivateHTMLFlavor(nsIClipboard* clipboard);
4214   nsresult ParseCFHTML(nsCString& aCfhtml, char16_t** aStuffToPaste,
4215                        char16_t** aCfcontext);
4216 
4217   nsresult StripFormattingNodes(nsIContent& aNode, bool aOnlyList = false);
4218   nsresult CreateDOMFragmentFromPaste(
4219       const nsAString& aInputString, const nsAString& aContextStr,
4220       const nsAString& aInfoStr, nsCOMPtr<nsINode>* aOutFragNode,
4221       nsCOMPtr<nsINode>* aOutStartNode, nsCOMPtr<nsINode>* aOutEndNode,
4222       int32_t* aOutStartOffset, int32_t* aOutEndOffset, bool aTrustedInput);
4223   nsresult ParseFragment(const nsAString& aStr, nsAtom* aContextLocalName,
4224                          Document* aTargetDoc,
4225                          dom::DocumentFragment** aFragment, bool aTrustedInput);
4226   /**
4227    * CollectTopMostChildContentsCompletelyInRange() collects topmost child
4228    * contents which are completely in the given range.
4229    * For example, if the range points a node with its container node, the
4230    * result is only the node (meaning does not include its descendants).
4231    * If the range starts start of a node and ends end of it, and if the node
4232    * does not have children, returns no nodes, otherwise, if the node has
4233    * some children, the result includes its all children (not including their
4234    * descendants).
4235    *
4236    * @param aStartPoint         Start point of the range.
4237    * @param aEndPoint           End point of the range.
4238    * @param aOutArrayOfContents [Out] Topmost children which are completely in
4239    *                            the range.
4240    */
4241   static void CollectTopMostChildNodesCompletelyInRange(
4242       const EditorRawDOMPoint& aStartPoint, const EditorRawDOMPoint& aEndPoint,
4243       nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents);
4244 
4245   /**
4246    * AutoHTMLFragmentBoundariesFixer fixes both edges of topmost child nodes
4247    * which are created with SubtreeContentIterator.
4248    */
4249   class MOZ_STACK_CLASS AutoHTMLFragmentBoundariesFixer final {
4250    public:
4251     /**
4252      * @param aArrayOfTopMostChildContents
4253      *                         [in/out] The topmost child nodes which will be
4254      *                         inserted into the DOM tree.  Both edges, i.e.,
4255      *                         first node and last node in this array will be
4256      *                         checked whether they can be insertted into
4257      *                         another DOM tree.  If not, it'll replaces some
4258      *                         orphan nodes around nodes with proper parent.
4259      */
4260     explicit AutoHTMLFragmentBoundariesFixer(
4261         nsTArray<OwningNonNull<nsIContent>>& aArrayOfTopMostChildContents);
4262 
4263    private:
4264     /**
4265      * EnsureBeginsOrEndsWithValidContent() replaces some nodes starting from
4266      * start or end with proper element node if it's necessary.
4267      * If first or last node of aArrayOfTopMostChildContents is in list and/or
4268      * `<table>` element, looks for topmost list element or `<table>` element
4269      * with `CollectListAndTableRelatedElementsAt()` and
4270      * `GetMostAncestorListOrTableElement()`.  Then, checks whether
4271      * some nodes are in aArrayOfTopMostChildContents are the topmost list/table
4272      * element or its descendant and if so, removes the nodes from
4273      * aArrayOfTopMostChildContents and inserts the list/table element instead.
4274      * Then, aArrayOfTopMostChildContents won't start/end with list-item nor
4275      * table cells.
4276      */
4277     enum class StartOrEnd { start, end };
4278     void EnsureBeginsOrEndsWithValidContent(
4279         StartOrEnd aStartOrEnd,
4280         nsTArray<OwningNonNull<nsIContent>>& aArrayOfTopMostChildContents)
4281         const;
4282 
4283     /**
4284      * CollectListAndTableRelatedElementsAt() collects list elements and
4285      * table related elements from aNode (meaning aNode may be in the first of
4286      * the result) to the root element.
4287      */
4288     void CollectListAndTableRelatedElementsAt(
4289         nsIContent& aContent,
4290         nsTArray<OwningNonNull<Element>>& aOutArrayOfListAndTableElements)
4291         const;
4292 
4293     /**
4294      * GetMostAncestorListOrTableElement() returns a list or a `<table>`
4295      * element which is in aArrayOfListAndTableElements and they are
4296      * actually valid ancestor of at least one of aArrayOfTopMostChildContents.
4297      */
4298     Element* GetMostAncestorListOrTableElement(
4299         const nsTArray<OwningNonNull<nsIContent>>& aArrayOfTopMostChildContents,
4300         const nsTArray<OwningNonNull<Element>>&
4301             aArrayOfListAndTableRelatedElements) const;
4302 
4303     /**
4304      * FindReplaceableTableElement() is a helper method of
4305      * EnsureBeginsOrEndsWithValidContent().  If aNodeMaybeInTableElement is
4306      * a descendant of aTableElement, returns aNodeMaybeInTableElement or its
4307      * nearest ancestor whose tag name is `<td>`, `<th>`, `<tr>`, `<thead>`,
4308      * `<tfoot>`, `<tbody>` or `<caption>`.
4309      *
4310      * @param aTableElement               Must be a `<table>` element.
4311      * @param aContentMaybeInTableElement A node which may be in aTableElement.
4312      */
4313     Element* FindReplaceableTableElement(
4314         Element& aTableElement, nsIContent& aContentMaybeInTableElement) const;
4315 
4316     /**
4317      * IsReplaceableListElement() is a helper method of
4318      * EnsureBeginsOrEndsWithValidContent().  If aNodeMaybeInListElement is a
4319      * descendant of aListElement, returns true.  Otherwise, false.
4320      *
4321      * @param aListElement                Must be a list element.
4322      * @param aContentMaybeInListElement  A node which may be in aListElement.
4323      */
4324     bool IsReplaceableListElement(Element& aListElement,
4325                                   nsIContent& aContentMaybeInListElement) const;
4326   };
4327 
4328   /**
4329    * GetBetterInsertionPointFor() returns better insertion point to insert
4330    * aContentToInsert.
4331    *
4332    * @param aContentToInsert    The content to insert.
4333    * @param aPointToInsert      A candidate point to insert the node.
4334    * @return                    Better insertion point if next visible node
4335    *                            is a <br> element and previous visible node
4336    *                            is neither none, another <br> element nor
4337    *                            different block level element.
4338    */
4339   EditorRawDOMPoint GetBetterInsertionPointFor(
4340       nsIContent& aContentToInsert, const EditorRawDOMPoint& aPointToInsert);
4341 
4342   /**
4343    * MakeDefinitionListItemWithTransaction() replaces parent list of current
4344    * selection with <dl> or create new <dl> element and creates a definition
4345    * list item whose name is aTagName.
4346    *
4347    * @param aTagName            Must be nsGkAtoms::dt or nsGkAtoms::dd.
4348    */
4349   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4350   MakeDefinitionListItemWithTransaction(nsAtom& aTagName);
4351 
4352   /**
4353    * FormatBlockContainerAsSubAction() inserts a block element whose name
4354    * is aTagName at selection.  If selection is not collapsed and aTagName is
4355    * nsGkAtoms::normal or nsGkAtoms::_empty, this removes block containers.
4356    *
4357    * @param aTagName            A block level element name.  Must NOT be
4358    *                            nsGkAtoms::dt nor nsGkAtoms::dd.
4359    */
4360   MOZ_CAN_RUN_SCRIPT nsresult FormatBlockContainerAsSubAction(nsAtom& aTagName);
4361 
4362   /**
4363    * Increase/decrease the font size of selection.
4364    */
4365   MOZ_CAN_RUN_SCRIPT nsresult RelativeFontChange(FontSize aDir);
4366 
4367   MOZ_CAN_RUN_SCRIPT nsresult RelativeFontChangeOnNode(int32_t aSizeChange,
4368                                                        nsIContent* aNode);
4369   MOZ_CAN_RUN_SCRIPT nsresult RelativeFontChangeHelper(int32_t aSizeChange,
4370                                                        nsINode* aNode);
4371 
4372   /**
4373    * Helper routines for inline style.
4374    */
4375   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertyOnTextNode(
4376       Text& aData, uint32_t aStartOffset, uint32_t aEndOffset,
4377       nsAtom& aProperty, nsAtom* aAttribute, const nsAString& aValue);
4378 
4379   nsresult PromoteInlineRange(nsRange& aRange);
4380   nsresult PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange& aRange);
4381 
4382   /**
4383    * RemoveStyleInside() removes elements which represent aProperty/aAttribute
4384    * and removes CSS style.  This handles aElement and all its descendants
4385    * (including leaf text nodes) recursively.
4386    */
4387   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4388   RemoveStyleInside(Element& aElement, nsAtom* aProperty, nsAtom* aAttribute);
4389 
4390   /**
4391    * CollectEditableLeafTextNodes() collects text nodes in aElement.
4392    */
4393   void CollectEditableLeafTextNodes(
4394       Element& aElement, nsTArray<OwningNonNull<Text>>& aLeafTextNodes) const;
4395 
4396   /**
4397    * IsRemovableParentStyleWithNewSpanElement() checks whether
4398    * aProperty/aAttribute of parent block can be removed from aContent with
4399    * creating `<span>` element.  Note that this does NOT check whether the
4400    * specified style comes from parent block or not.
4401    * XXX This may destroy the editor, but using `Result<bool, nsresult>`
4402    *     is not reasonable because code for accessing the result becomes
4403    *     messy.  However, anybody must forget to check `Destroyed()` after
4404    *     calling this.  Which is the way to smart to make every caller
4405    *     must check the editor state?
4406    */
4407   MOZ_CAN_RUN_SCRIPT bool IsRemovableParentStyleWithNewSpanElement(
4408       nsIContent& aContent, nsAtom* aHTMLProperty, nsAtom* aAttribute) const;
4409 
4410   /**
4411    * XXX These methods seem odd and except the only caller,
4412    *     `PromoteInlineRange()`, cannot use them.
4413    */
4414   bool IsStartOfContainerOrBeforeFirstEditableChild(
4415       const EditorRawDOMPoint& aPoint) const;
4416   bool IsEndOfContainerOrEqualsOrAfterLastEditableChild(
4417       const EditorRawDOMPoint& aPoint) const;
4418 
4419   bool IsOnlyAttribute(const Element* aElement, nsAtom* aAttribute);
4420 
4421   /**
4422    * HasStyleOrIdOrClassAttribute() returns true when at least one of
4423    * `style`, `id` or `class` attribute value of aElement is not empty.
4424    */
4425   static bool HasStyleOrIdOrClassAttribute(Element& aElement);
4426 
4427   /**
4428    * Whether the outer window of the DOM event target has focus or not.
4429    */
4430   bool OurWindowHasFocus() const;
4431 
4432   /**
4433    * This function is used to insert a string of HTML input optionally with some
4434    * context information into the editable field.  The HTML input either comes
4435    * from a transferable object created as part of a drop/paste operation, or
4436    * from the InsertHTML method.  We may want the HTML input to be sanitized
4437    * (for example, if it's coming from a transferable object), in which case
4438    * aTrustedInput should be set to false, otherwise, the caller should set it
4439    * to true, which means that the HTML will be inserted in the DOM verbatim.
4440    *
4441    * aClearStyle should be set to false if you want the paste to be affected by
4442    * local style (e.g., for the insertHTML command).
4443    */
4444   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult DoInsertHTMLWithContext(
4445       const nsAString& aInputString, const nsAString& aContextStr,
4446       const nsAString& aInfoStr, const nsAString& aFlavor, Document* aSourceDoc,
4447       const EditorDOMPoint& aPointToInsert, bool aDeleteSelection,
4448       bool aTrustedInput, bool aClearStyle = true);
4449 
4450   /**
4451    * sets the position of an element; warning it does NOT check if the
4452    * element is already positioned or not and that's on purpose.
4453    * @param aElement [IN] the element
4454    * @param aX       [IN] the x position in pixels.
4455    * @param aY       [IN] the y position in pixels.
4456    */
4457   MOZ_CAN_RUN_SCRIPT void SetTopAndLeft(Element& aElement, int32_t aX,
4458                                         int32_t aY);
4459 
4460   /**
4461    * Reset a selected cell or collapsed selection (the caret) after table
4462    * editing.
4463    *
4464    * @param aTable      A table in the document.
4465    * @param aRow        The row ...
4466    * @param aCol        ... and column defining the cell where we will try to
4467    *                    place the caret.
4468    * @param aSelected   If true, we select the whole cell instead of setting
4469    *                    caret.
4470    * @param aDirection  If cell at (aCol, aRow) is not found, search for
4471    *                    previous cell in the same column (aPreviousColumn) or
4472    *                    row (ePreviousRow) or don't search for another cell
4473    *                    (aNoSearch).  If no cell is found, caret is place just
4474    *                    before table; and if that fails, at beginning of
4475    *                    document.  Thus we generally don't worry about the
4476    *                    return value and can use the
4477    *                    AutoSelectionSetterAfterTableEdit stack-based object to
4478    *                    insure we reset the caret in a table-editing method.
4479    */
4480   MOZ_CAN_RUN_SCRIPT void SetSelectionAfterTableEdit(Element* aTable,
4481                                                      int32_t aRow, int32_t aCol,
4482                                                      int32_t aDirection,
4483                                                      bool aSelected);
4484 
4485   void RemoveListenerAndDeleteRef(const nsAString& aEvent,
4486                                   nsIDOMEventListener* aListener,
4487                                   bool aUseCapture, ManualNACPtr aElement,
4488                                   PresShell* aPresShell);
4489   void DeleteRefToAnonymousNode(ManualNACPtr aContent, PresShell* aPresShell);
4490 
4491   /**
4492    * RefreshEditingUI() may refresh editing UIs for current Selection, focus,
4493    * etc.  If this shows or hides some UIs, it causes reflow.  So, this is
4494    * not safe method.
4495    */
4496   MOZ_CAN_RUN_SCRIPT nsresult RefreshEditingUI();
4497 
4498   /**
4499    * Returns the offset of an element's frame to its absolute containing block.
4500    */
4501   nsresult GetElementOrigin(Element& aElement, int32_t& aX, int32_t& aY);
4502   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetPositionAndDimensions(
4503       Element& aElement, int32_t& aX, int32_t& aY, int32_t& aW, int32_t& aH,
4504       int32_t& aBorderLeft, int32_t& aBorderTop, int32_t& aMarginLeft,
4505       int32_t& aMarginTop);
4506 
4507   bool IsInObservedSubtree(nsIContent* aChild);
4508 
4509   void UpdateRootElement();
4510 
4511   /**
4512    * SetAllResizersPosition() moves all resizers to proper position.
4513    * If the resizers are hidden or replaced with another set of resizers
4514    * while this is running, this returns error.  So, callers shouldn't
4515    * keep handling the resizers if this returns error.
4516    */
4517   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetAllResizersPosition();
4518 
4519   /**
4520    * Shows active resizers around an element's frame
4521    * @param aResizedElement [IN] a DOM Element
4522    */
4523   MOZ_CAN_RUN_SCRIPT nsresult ShowResizersInternal(Element& aResizedElement);
4524 
4525   /**
4526    * Hide resizers if they are visible.  If this is called while there is no
4527    * visible resizers, this does not return error, but does nothing.
4528    */
4529   nsresult HideResizersInternal();
4530 
4531   /**
4532    * RefreshResizersInternal() moves resizers to proper position.  This does
4533    * nothing if there is no resizing target.
4534    */
4535   MOZ_CAN_RUN_SCRIPT nsresult RefreshResizersInternal();
4536 
4537   ManualNACPtr CreateResizer(int16_t aLocation, nsIContent& aParentContent);
4538   MOZ_CAN_RUN_SCRIPT void SetAnonymousElementPosition(int32_t aX, int32_t aY,
4539                                                       Element* aResizer);
4540 
4541   ManualNACPtr CreateShadow(nsIContent& aParentContent,
4542                             Element& aOriginalObject);
4543 
4544   /**
4545    * SetShadowPosition() moves the shadow element to proper position.
4546    *
4547    * @param aShadowElement      Must be mResizingShadow or mPositioningShadow.
4548    * @param aElement            The element which has the shadow.
4549    * @param aElementX           Left of aElement.
4550    * @param aElementY           Top of aElement.
4551    */
4552   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4553   SetShadowPosition(Element& aShadowElement, Element& aElement,
4554                     int32_t aElementLeft, int32_t aElementTop);
4555 
4556   ManualNACPtr CreateResizingInfo(nsIContent& aParentContent);
4557   MOZ_CAN_RUN_SCRIPT nsresult SetResizingInfoPosition(int32_t aX, int32_t aY,
4558                                                       int32_t aW, int32_t aH);
4559 
4560   enum class ResizeAt {
4561     eX,
4562     eY,
4563     eWidth,
4564     eHeight,
4565   };
4566   int32_t GetNewResizingIncrement(int32_t aX, int32_t aY, ResizeAt aResizeAt);
4567 
4568   MOZ_CAN_RUN_SCRIPT nsresult StartResizing(Element* aHandle);
4569   int32_t GetNewResizingX(int32_t aX, int32_t aY);
4570   int32_t GetNewResizingY(int32_t aX, int32_t aY);
4571   int32_t GetNewResizingWidth(int32_t aX, int32_t aY);
4572   int32_t GetNewResizingHeight(int32_t aX, int32_t aY);
4573   void HideShadowAndInfo();
4574   MOZ_CAN_RUN_SCRIPT void SetFinalSize(int32_t aX, int32_t aY);
4575   void SetResizeIncrements(int32_t aX, int32_t aY, int32_t aW, int32_t aH,
4576                            bool aPreserveRatio);
4577 
4578   /**
4579    * HideAnonymousEditingUIs() forcibly hides all editing UIs (resizers,
4580    * inline-table-editing UI, absolute positioning UI).
4581    */
4582   void HideAnonymousEditingUIs();
4583 
4584   /**
4585    * HideAnonymousEditingUIsIfUnnecessary() hides all editing UIs if some of
4586    * visible UIs are now unnecessary.
4587    */
4588   void HideAnonymousEditingUIsIfUnnecessary();
4589 
4590   /**
4591    * sets the z-index of an element.
4592    * @param aElement [IN] the element
4593    * @param aZorder  [IN] the z-index
4594    */
4595   MOZ_CAN_RUN_SCRIPT void SetZIndex(Element& aElement, int32_t aZorder);
4596 
4597   /**
4598    * shows a grabber attached to an arbitrary element. The grabber is an image
4599    * positioned on the left hand side of the top border of the element. Draggin
4600    * and dropping it allows to change the element's absolute position in the
4601    * document. See chrome://editor/content/images/grabber.gif
4602    * @param aElement [IN] the element
4603    */
4604   MOZ_CAN_RUN_SCRIPT nsresult ShowGrabberInternal(Element& aElement);
4605 
4606   /**
4607    * Setting grabber to proper position for current mAbsolutelyPositionedObject.
4608    * For example, while an element has grabber, the element may be resized
4609    * or repositioned by script or something.  Then, you need to reset grabber
4610    * position with this.
4611    */
4612   MOZ_CAN_RUN_SCRIPT nsresult RefreshGrabberInternal();
4613 
4614   /**
4615    * hide the grabber if it shown.
4616    */
4617   void HideGrabberInternal();
4618 
4619   /**
4620    * CreateGrabberInternal() creates a grabber for moving aParentContent.
4621    * This sets mGrabber to the new grabber.  If this returns true, it's
4622    * always non-nullptr.  Otherwise, i.e., the grabber is hidden during
4623    * creation, this returns false.
4624    */
4625   bool CreateGrabberInternal(nsIContent& aParentContent);
4626 
4627   MOZ_CAN_RUN_SCRIPT nsresult StartMoving();
4628   MOZ_CAN_RUN_SCRIPT nsresult SetFinalPosition(int32_t aX, int32_t aY);
4629   void AddPositioningOffset(int32_t& aX, int32_t& aY);
4630   void SnapToGrid(int32_t& newX, int32_t& newY);
4631   nsresult GrabberClicked();
4632   MOZ_CAN_RUN_SCRIPT nsresult EndMoving();
4633   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4634   GetTemporaryStyleForFocusedPositionedElement(Element& aElement,
4635                                                nsAString& aReturn);
4636 
4637   /**
4638    * Shows inline table editing UI around a <table> element which contains
4639    * aCellElement.  This returns error if creating UI is hidden during this,
4640    * or detects another set of UI during this.  In such case, callers
4641    * shouldn't keep handling anything for the UI.
4642    *
4643    * @param aCellElement    Must be an <td> or <th> element.
4644    */
4645   MOZ_CAN_RUN_SCRIPT nsresult
4646   ShowInlineTableEditingUIInternal(Element& aCellElement);
4647 
4648   /**
4649    * Hide all inline table editing UI.
4650    */
4651   void HideInlineTableEditingUIInternal();
4652 
4653   /**
4654    * RefreshInlineTableEditingUIInternal() moves inline table editing UI to
4655    * proper position.  This returns error if the UI is hidden or replaced
4656    * during moving.
4657    */
4658   MOZ_CAN_RUN_SCRIPT nsresult RefreshInlineTableEditingUIInternal();
4659 
4660   /**
4661    * IsEmptyTextNode() returns true if aNode is a text node and does not have
4662    * any visible characters.
4663    */
IsEmptyTextNode(nsINode & aNode)4664   bool IsEmptyTextNode(nsINode& aNode) const {
4665     return aNode.IsText() && IsEmptyNode(aNode);
4666   }
4667 
4668   MOZ_CAN_RUN_SCRIPT bool IsSimpleModifiableNode(nsIContent* aContent,
4669                                                  nsAtom* aProperty,
4670                                                  nsAtom* aAttribute,
4671                                                  const nsAString* aValue);
4672   MOZ_CAN_RUN_SCRIPT nsresult
4673   SetInlinePropertyOnNodeImpl(nsIContent& aNode, nsAtom& aProperty,
4674                               nsAtom* aAttribute, const nsAString& aValue);
4675   typedef enum { eInserted, eAppended } InsertedOrAppended;
4676   MOZ_CAN_RUN_SCRIPT void DoContentInserted(
4677       nsIContent* aChild, InsertedOrAppended aInsertedOrAppended);
4678 
4679   /**
4680    * Returns an anonymous Element of type aTag,
4681    * child of aParentContent. If aIsCreatedHidden is true, the class
4682    * "hidden" is added to the created element. If aAnonClass is not
4683    * the empty string, it becomes the value of the attribute "_moz_anonclass"
4684    * @return a Element
4685    * @param aTag             [IN] desired type of the element to create
4686    * @param aParentContent   [IN] the parent node of the created anonymous
4687    *                              element
4688    * @param aAnonClass       [IN] contents of the _moz_anonclass attribute
4689    * @param aIsCreatedHidden [IN] a boolean specifying if the class "hidden"
4690    *                              is to be added to the created anonymous
4691    *                              element
4692    */
4693   ManualNACPtr CreateAnonymousElement(nsAtom* aTag, nsIContent& aParentContent,
4694                                       const nsAString& aAnonClass,
4695                                       bool aIsCreatedHidden);
4696 
4697   /**
4698    * Reads a blob into memory and notifies the BlobReader object when the read
4699    * operation is finished.
4700    *
4701    * @param aBlob       The input blob
4702    * @param aWindow     The global object under which the read should happen.
4703    * @param aBlobReader The blob reader object to be notified when finished.
4704    */
4705   static nsresult SlurpBlob(dom::Blob* aBlob, nsPIDOMWindowOuter* aWindow,
4706                             BlobReader* aBlobReader);
4707 
4708   /**
4709    * OnModifyDocumentInternal() is called by OnModifyDocument().
4710    */
4711   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult OnModifyDocumentInternal();
4712 
4713   /**
4714    * For saving allocation cost in the constructor of
4715    * EditorBase::TopLevelEditSubActionData, we should reuse same RangeItem
4716    * instance with all top level edit sub actions.
4717    * The instance is always cleared when TopLevelEditSubActionData is
4718    * destructed and the class is stack only class so that we don't need
4719    * to (and also should not) add the RangeItem into the cycle collection.
4720    */
GetSelectedRangeItemForTopLevelEditSubAction()4721   already_AddRefed<RangeItem> GetSelectedRangeItemForTopLevelEditSubAction()
4722       const {
4723     if (!mSelectedRangeForTopLevelEditSubAction) {
4724       mSelectedRangeForTopLevelEditSubAction = new RangeItem();
4725     }
4726     return do_AddRef(mSelectedRangeForTopLevelEditSubAction);
4727   }
4728 
4729   /**
4730    * For saving allocation cost in the constructor of
4731    * EditorBase::TopLevelEditSubActionData, we should reuse same nsRange
4732    * instance with all top level edit sub actions.
4733    * The instance is always cleared when TopLevelEditSubActionData is
4734    * destructed, but AbstractRange::mOwner keeps grabbing the owner document
4735    * so that we need to make it in the cycle collection.
4736    */
GetChangedRangeForTopLevelEditSubAction()4737   already_AddRefed<nsRange> GetChangedRangeForTopLevelEditSubAction() const {
4738     if (!mChangedRangeForTopLevelEditSubAction) {
4739       mChangedRangeForTopLevelEditSubAction = nsRange::Create(GetDocument());
4740     }
4741     return do_AddRef(mChangedRangeForTopLevelEditSubAction);
4742   }
4743 
4744  protected:
4745   // Helper for Handle[CSS|HTML]IndentAtSelectionInternal
4746   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4747   IndentListChild(RefPtr<Element>* aCurList, const EditorDOMPoint& aCurPoint,
4748                   nsIContent& aContent);
4749 
4750   RefPtr<TypeInState> mTypeInState;
4751   RefPtr<ComposerCommandsUpdater> mComposerCommandsUpdater;
4752 
4753   // Used by TopLevelEditSubActionData::mSelectedRange.
4754   mutable RefPtr<RangeItem> mSelectedRangeForTopLevelEditSubAction;
4755   // Used by TopLevelEditSubActionData::mChangedRange.
4756   mutable RefPtr<nsRange> mChangedRangeForTopLevelEditSubAction;
4757 
4758   RefPtr<Runnable> mPendingRootElementUpdatedRunner;
4759   RefPtr<Runnable> mPendingDocumentModifiedRunner;
4760 
4761   bool mCRInParagraphCreatesParagraph;
4762 
4763   bool mCSSAware;
4764   UniquePtr<CSSEditUtils> mCSSEditUtils;
4765 
4766   // mSelectedCellIndex is reset by GetFirstSelectedTableCellElement(),
4767   // then, it'll be referred and incremented by
4768   // GetNextSelectedTableCellElement().
4769   mutable uint32_t mSelectedCellIndex;
4770 
4771   // resizing
4772   bool mIsObjectResizingEnabled;
4773   bool mIsResizing;
4774   bool mPreserveRatio;
4775   bool mResizedObjectIsAnImage;
4776 
4777   // absolute positioning
4778   bool mIsAbsolutelyPositioningEnabled;
4779   bool mResizedObjectIsAbsolutelyPositioned;
4780   bool mGrabberClicked;
4781   bool mIsMoving;
4782 
4783   bool mSnapToGridEnabled;
4784 
4785   // inline table editing
4786   bool mIsInlineTableEditingEnabled;
4787 
4788   // resizing
4789   ManualNACPtr mTopLeftHandle;
4790   ManualNACPtr mTopHandle;
4791   ManualNACPtr mTopRightHandle;
4792   ManualNACPtr mLeftHandle;
4793   ManualNACPtr mRightHandle;
4794   ManualNACPtr mBottomLeftHandle;
4795   ManualNACPtr mBottomHandle;
4796   ManualNACPtr mBottomRightHandle;
4797 
4798   RefPtr<Element> mActivatedHandle;
4799 
4800   ManualNACPtr mResizingShadow;
4801   ManualNACPtr mResizingInfo;
4802 
4803   RefPtr<Element> mResizedObject;
4804 
4805   int32_t mOriginalX;
4806   int32_t mOriginalY;
4807 
4808   int32_t mResizedObjectX;
4809   int32_t mResizedObjectY;
4810   int32_t mResizedObjectWidth;
4811   int32_t mResizedObjectHeight;
4812 
4813   int32_t mResizedObjectMarginLeft;
4814   int32_t mResizedObjectMarginTop;
4815   int32_t mResizedObjectBorderLeft;
4816   int32_t mResizedObjectBorderTop;
4817 
4818   int32_t mXIncrementFactor;
4819   int32_t mYIncrementFactor;
4820   int32_t mWidthIncrementFactor;
4821   int32_t mHeightIncrementFactor;
4822 
4823   int8_t mInfoXIncrement;
4824   int8_t mInfoYIncrement;
4825 
4826   // absolute positioning
4827   int32_t mPositionedObjectX;
4828   int32_t mPositionedObjectY;
4829   int32_t mPositionedObjectWidth;
4830   int32_t mPositionedObjectHeight;
4831 
4832   int32_t mPositionedObjectMarginLeft;
4833   int32_t mPositionedObjectMarginTop;
4834   int32_t mPositionedObjectBorderLeft;
4835   int32_t mPositionedObjectBorderTop;
4836 
4837   RefPtr<Element> mAbsolutelyPositionedObject;
4838   ManualNACPtr mGrabber;
4839   ManualNACPtr mPositioningShadow;
4840 
4841   int32_t mGridSize;
4842 
4843   // inline table editing
4844   RefPtr<Element> mInlineEditedCell;
4845 
4846   ManualNACPtr mAddColumnBeforeButton;
4847   ManualNACPtr mRemoveColumnButton;
4848   ManualNACPtr mAddColumnAfterButton;
4849 
4850   ManualNACPtr mAddRowBeforeButton;
4851   ManualNACPtr mRemoveRowButton;
4852   ManualNACPtr mAddRowAfterButton;
4853 
4854   void AddMouseClickListener(Element* aElement);
4855   void RemoveMouseClickListener(Element* aElement);
4856 
4857   bool mDisabledLinkHandling = false;
4858   bool mOldLinkHandlingEnabled = false;
4859 
4860   ParagraphSeparator mDefaultParagraphSeparator;
4861 
4862   friend class AlignStateAtSelection;
4863   friend class AutoSelectionSetterAfterTableEdit;
4864   friend class AutoSetTemporaryAncestorLimiter;
4865   friend class CSSEditUtils;
4866   friend class EditorBase;
4867   friend class EmptyEditableFunctor;
4868   friend class JoinNodeTransaction;
4869   friend class ListElementSelectionState;
4870   friend class ListItemElementSelectionState;
4871   friend class ParagraphStateAtSelection;
4872   friend class SlurpBlobEventListener;
4873   friend class SplitNodeTransaction;
4874   friend class TextEditor;
4875   friend class WSRunObject;
4876   friend class WSRunScanner;
4877   friend class WSScanResult;
4878 };
4879 
4880 /**
4881  * ListElementSelectionState class gets which list element is selected right
4882  * now.
4883  */
4884 class MOZ_STACK_CLASS ListElementSelectionState final {
4885  public:
4886   ListElementSelectionState() = delete;
4887   ListElementSelectionState(HTMLEditor& aHTMLEditor, ErrorResult& aRv);
4888 
IsOLElementSelected()4889   bool IsOLElementSelected() const { return mIsOLElementSelected; }
IsULElementSelected()4890   bool IsULElementSelected() const { return mIsULElementSelected; }
IsDLElementSelected()4891   bool IsDLElementSelected() const { return mIsDLElementSelected; }
IsNotOneTypeListElementSelected()4892   bool IsNotOneTypeListElementSelected() const {
4893     return (mIsOLElementSelected + mIsULElementSelected + mIsDLElementSelected +
4894             mIsOtherContentSelected) > 1;
4895   }
4896 
4897  private:
4898   bool mIsOLElementSelected = false;
4899   bool mIsULElementSelected = false;
4900   bool mIsDLElementSelected = false;
4901   bool mIsOtherContentSelected = false;
4902 };
4903 
4904 /**
4905  * ListItemElementSelectionState class gets which list item element is selected
4906  * right now.
4907  */
4908 class MOZ_STACK_CLASS ListItemElementSelectionState final {
4909  public:
4910   ListItemElementSelectionState() = delete;
4911   ListItemElementSelectionState(HTMLEditor& aHTMLEditor, ErrorResult& aRv);
4912 
IsLIElementSelected()4913   bool IsLIElementSelected() const { return mIsLIElementSelected; }
IsDTElementSelected()4914   bool IsDTElementSelected() const { return mIsDTElementSelected; }
IsDDElementSelected()4915   bool IsDDElementSelected() const { return mIsDDElementSelected; }
IsNotOneTypeDefinitionListItemElementSelected()4916   bool IsNotOneTypeDefinitionListItemElementSelected() const {
4917     return (mIsDTElementSelected + mIsDDElementSelected +
4918             mIsOtherElementSelected) > 1;
4919   }
4920 
4921  private:
4922   bool mIsLIElementSelected = false;
4923   bool mIsDTElementSelected = false;
4924   bool mIsDDElementSelected = false;
4925   bool mIsOtherElementSelected = false;
4926 };
4927 
4928 /**
4929  * AlignStateAtSelection class gets alignment at selection.
4930  * XXX This currently returns only first alignment.
4931  */
4932 class MOZ_STACK_CLASS AlignStateAtSelection final {
4933  public:
4934   AlignStateAtSelection() = delete;
4935   MOZ_CAN_RUN_SCRIPT AlignStateAtSelection(HTMLEditor& aHTMLEditor,
4936                                            ErrorResult& aRv);
4937 
AlignmentAtSelectionStart()4938   nsIHTMLEditor::EAlignment AlignmentAtSelectionStart() const {
4939     return mFirstAlign;
4940   }
IsSelectionRangesFound()4941   bool IsSelectionRangesFound() const { return mFoundSelectionRanges; }
4942 
4943  private:
4944   nsIHTMLEditor::EAlignment mFirstAlign = nsIHTMLEditor::eLeft;
4945   bool mFoundSelectionRanges = false;
4946 };
4947 
4948 /**
4949  * ParagraphStateAtSelection class gets format block types around selection.
4950  */
4951 class MOZ_STACK_CLASS ParagraphStateAtSelection final {
4952  public:
4953   ParagraphStateAtSelection() = delete;
4954   ParagraphStateAtSelection(HTMLEditor& aHTMLEditor, ErrorResult& aRv);
4955 
4956   /**
4957    * GetFirstParagraphStateAtSelection() returns:
4958    * - nullptr if there is no format blocks nor inline nodes.
4959    * - nsGkAtoms::_empty if first node is not in any format block.
4960    * - a tag name of format block at first node.
4961    * XXX See the private method explanations.  If selection ranges contains
4962    *     non-format block first, it'll be check after its siblings.  Therefore,
4963    *     this may return non-first paragraph state.
4964    */
GetFirstParagraphStateAtSelection()4965   nsAtom* GetFirstParagraphStateAtSelection() const {
4966     return mFirstParagraphState;
4967   }
4968 
4969   /**
4970    * If selected nodes are not in same format node nor only in no-format blocks,
4971    * this returns true.
4972    */
IsMixed()4973   bool IsMixed() const { return mIsMixed; }
4974 
4975  private:
4976   using EditorType = EditorBase::EditorType;
4977 
4978   /**
4979    * AppendDescendantFormatNodesAndFirstInlineNode() appends descendant
4980    * format blocks and first inline child node in aNonFormatBlockElement to
4981    * the last of the array (not inserting where aNonFormatBlockElement is,
4982    * so that the node order becomes randomly).
4983    *
4984    * @param aArrayOfContents            [in/out] Found descendant format blocks
4985    *                                    and first inline node in each non-format
4986    *                                    block will be appended to this.
4987    * @param aNonFormatBlockElement      Must be a non-format block element.
4988    */
4989   static void AppendDescendantFormatNodesAndFirstInlineNode(
4990       nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
4991       dom::Element& aNonFormatBlockElement);
4992 
4993   /**
4994    * CollectEditableFormatNodesInSelection() collects only editable nodes
4995    * around selection ranges (with
4996    * `HTMLEditor::CollectEditTargetNodesInExtendedSelectionRanges()`, see its
4997    * document for the detail).  If it includes list, list item or table
4998    * related elements, they will be replaced their children.
4999    */
5000   static nsresult CollectEditableFormatNodesInSelection(
5001       HTMLEditor& aHTMLEditor,
5002       nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents);
5003 
5004   RefPtr<nsAtom> mFirstParagraphState;
5005   bool mIsMixed = false;
5006 };
5007 
5008 }  // namespace mozilla
5009 
AsHTMLEditor()5010 mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() {
5011   return static_cast<mozilla::EditorBase*>(this)->IsHTMLEditor()
5012              ? static_cast<mozilla::HTMLEditor*>(this)
5013              : nullptr;
5014 }
5015 
AsHTMLEditor()5016 const mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() const {
5017   return static_cast<const mozilla::EditorBase*>(this)->IsHTMLEditor()
5018              ? static_cast<const mozilla::HTMLEditor*>(this)
5019              : nullptr;
5020 }
5021 
5022 #endif  // #ifndef mozilla_HTMLEditor_h
5023