tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HTMLEditor.h (216363B)


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