Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/editor/libeditor/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 210 kB image not shown  

Quelle  HTMLEditor.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef mozilla_HTMLEditor_h
#define mozilla_HTMLEditor_h

#include "mozilla/Attributes.h"
#include "mozilla/ComposerCommandsUpdater.h"
#include "mozilla/EditorBase.h"
#include "mozilla/EditorForwards.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/ManualNAC.h"
#include "mozilla/Result.h"
#include "mozilla/dom/BlobImpl.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/File.h"

#include "nsAttrName.h"
#include "nsCOMPtr.h"
#include "nsIDocumentObserver.h"
#include "nsIDOMEventListener.h"
#include "nsIEditorMailSupport.h"
#include "nsIHTMLAbsPosEditor.h"
#include "nsIHTMLEditor.h"
#include "nsIHTMLInlineTableEditor.h"
#include "nsIHTMLObjectResizer.h"
#include "nsIPrincipal.h"
#include "nsITableEditor.h"
#include "nsPoint.h"
#include "nsStubMutationObserver.h"

#include <functional>

class nsDocumentFragment;
class nsFrameSelection;
class nsHTMLDocument;
class nsITransferable;
class nsRange;
class nsStaticAtom;
class nsStyledElement;
class nsTableCellFrame;
class nsTableWrapperFrame;
template <class E>
class nsTArray;

namespace mozilla {
class AlignStateAtSelection;
class AutoSelectionSetterAfterTableEdit;
class EmptyEditableFunctor;
class ListElementSelectionState;
class ListItemElementSelectionState;
class ParagraphStateAtSelection;
class ResizerSelectionListener;
class Runnable;
template <class T>
class OwningNonNull;
namespace dom {
class AbstractRange;
class Blob;
class DocumentFragment;
class Event;
class HTMLBRElement;
class MouseEvent;
class StaticRange;
}  // namespace dom
namespace widget {
struct IMEState;
}  // namespace widget

enum class ParagraphSeparator { div, p, br };

/**
 * The HTML editor implementation.<br>
 * Use to edit HTML document represented as a DOM tree.
 */

class HTMLEditor final : public EditorBase,
                         public nsIHTMLEditor,
                         public nsIHTMLObjectResizer,
                         public nsIHTMLAbsPosEditor,
                         public nsITableEditor,
                         public nsIHTMLInlineTableEditor,
                         public nsStubMutationObserver,
                         public nsIEditorMailSupport {
 public:
  /****************************************************************************
   * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
   *       classes under libeditor except EditorEventListener and
   *       HTMLEditorEventListener because each public method which may fire
   *       eEditorInput event will need to instantiate new stack class for
   *       managing input type value of eEditorInput and cache some objects
   *       for smarter handling.  In other words, when you add new root
   *       method to edit the DOM tree, you can make your new method public.
   ****************************************************************************/


  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditor, EditorBase)

  // nsStubMutationObserver overrides
  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED

  // nsIHTMLEditor methods
  NS_DECL_NSIHTMLEDITOR

  // nsIHTMLObjectResizer methods (implemented in HTMLObjectResizer.cpp)
  NS_DECL_NSIHTMLOBJECTRESIZER

  // nsIHTMLAbsPosEditor methods (implemented in HTMLAbsPositionEditor.cpp)
  NS_DECL_NSIHTMLABSPOSEDITOR

  // nsIHTMLInlineTableEditor methods (implemented in HTMLInlineTableEditor.cpp)
  NS_DECL_NSIHTMLINLINETABLEEDITOR

  // nsIEditorMailSupport methods
  NS_DECL_NSIEDITORMAILSUPPORT

  // nsITableEditor methods
  NS_DECL_NSITABLEEDITOR

  // nsISelectionListener overrides
  NS_DECL_NSISELECTIONLISTENER

  /**
   * @param aDocument   The document whose content will be editable.
   */

  explicit HTMLEditor(const Document& aDocument);

  /**
   * @param aDocument   The document whose content will be editable.
   * @param aComposerCommandsUpdater     The composer command updater.
   * @param aFlags      Some of nsIEditor::eEditor*Mask flags.
   */

  MOZ_CAN_RUN_SCRIPT nsresult
  Init(Document& aDocument, ComposerCommandsUpdater& aComposerCommandsUpdater,
       uint32_t aFlags);

  /**
   * PostCreate() should be called after Init, and is the time that the editor
   * tells its documentStateObservers that the document has been created.
   */

  MOZ_CAN_RUN_SCRIPT nsresult PostCreate();

  /**
   * PreDestroy() is called before the editor goes away, and gives the editor a
   * chance to tell its documentStateObservers that the document is going away.
   */

  MOZ_CAN_RUN_SCRIPT void PreDestroy();

  static HTMLEditor* GetFrom(nsIEditor* aEditor) {
    return aEditor ? aEditor->GetAsHTMLEditor() : nullptr;
  }
  static const HTMLEditor* GetFrom(const nsIEditor* aEditor) {
    return aEditor ? aEditor->GetAsHTMLEditor() : nullptr;
  }

  [[nodiscard]] bool GetReturnInParagraphCreatesNewParagraph() const;

  // EditorBase overrides
  MOZ_CAN_RUN_SCRIPT NS_IMETHOD BeginningOfDocument() final;
  MOZ_CAN_RUN_SCRIPT NS_IMETHOD EndOfDocument() final;

  NS_IMETHOD GetDocumentCharacterSet(nsACString& aCharacterSet) final;
  MOZ_CAN_RUN_SCRIPT NS_IMETHOD
  SetDocumentCharacterSet(const nsACString& aCharacterSet) final;

  bool IsEmpty() const final;

  bool CanPaste(nsIClipboard::ClipboardType aClipboardType) const final;
  using EditorBase::CanPaste;

  MOZ_CAN_RUN_SCRIPT NS_IMETHOD DeleteNode(nsINode* aNode,
                                           bool aPreseveSelection,
                                           uint8_t aOptionalArgCount) final;

  MOZ_CAN_RUN_SCRIPT NS_IMETHOD InsertLineBreak() final;

  /**
   * PreHandleMouseDown() and PreHandleMouseUp() are called before
   * HTMLEditorEventListener handles them.  The coming event may be
   * non-acceptable event.
   */

  void PreHandleMouseDown(const dom::MouseEvent& aMouseDownEvent);
  void PreHandleMouseUp(const dom::MouseEvent& aMouseUpEvent);

  /**
   * PreHandleSelectionChangeCommand() and PostHandleSelectionChangeCommand()
   * are called before or after handling a command which may change selection
   * and/or scroll position.
   */

  void PreHandleSelectionChangeCommand(Command aCommand);
  void PostHandleSelectionChangeCommand(Command aCommand);

  MOZ_CAN_RUN_SCRIPT nsresult
  HandleKeyPressEvent(WidgetKeyboardEvent* aKeyboardEvent) final;
  Element* GetFocusedElement() const final;
  bool IsActiveInDOMWindow() const final;
  dom::EventTarget* GetDOMEventTarget() const final;
  [[nodiscard]] Element* FindSelectionRoot(const nsINode& aNode) const final;
  bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) const final;
  nsresult GetPreferredIMEState(widget::IMEState* aState) final;
  MOZ_CAN_RUN_SCRIPT nsresult
  OnFocus(const nsINode& aOriginalEventTargetNode) final;
  nsresult OnBlur(const dom::EventTarget* aEventTarget) final;

  /**
   * Called when aDocument or aElement becomes editable without focus change.
   * E.g., when the design mode is enabled or the contenteditable attribute
   * is set to the focused element.
   */

  MOZ_CAN_RUN_SCRIPT nsresult FocusedElementOrDocumentBecomesEditable(
      Document& aDocument, Element* aElement);

  /**
   * Called when aDocument or aElement becomes not editable without focus
   * change. E.g., when the design mode ends or the contenteditable attribute is
   * removed or set to "false".
   */

  MOZ_CAN_RUN_SCRIPT static nsresult FocusedElementOrDocumentBecomesNotEditable(
      HTMLEditor* aHTMLEditor, Document& aDocument, Element* aElement);

  /**
   * GetBackgroundColorState() returns what the background color of the
   * selection.
   *
   * @param aMixed      true if there is more than one font color
   * @param aOutColor   Color string. "" is returned for none.
   */

  MOZ_CAN_RUN_SCRIPT nsresult GetBackgroundColorState(bool* aMixed,
                                                      nsAString& aOutColor);

  /**
   * PasteNoFormattingAsAction() pastes content in clipboard without any style
   * information.
   *
   * @param aClipboardType      nsIClipboard::kGlobalClipboard or
   *                            nsIClipboard::kSelectionClipboard.
   * @param aDispatchPasteEvent Yes if this should dispatch ePaste event
   *                            before pasting.  Otherwise, No.
   * @param aDataTransfer       The object containing the data to use for the
   *                            paste operation. May be nullptr, in which case
   *                            this will just get the data from the clipboard.
   * @param aPrincipal          Set subject principal if it may be called by
   *                            JS.  If set to nullptr, will be treated as
   *                            called by system.
   */

  MOZ_CAN_RUN_SCRIPT nsresult
  PasteNoFormattingAsAction(nsIClipboard::ClipboardType aClipboardType,
                            DispatchPasteEvent aDispatchPasteEvent,
                            DataTransfer* aDataTransfer = nullptr,
                            nsIPrincipal* aPrincipal = nullptr);

  bool CanPasteTransferable(nsITransferable* aTransferable) final;

  MOZ_CAN_RUN_SCRIPT nsresult
  InsertLineBreakAsAction(nsIPrincipal* aPrincipal = nullptr) final;

  /**
   * InsertParagraphSeparatorAsAction() is called when user tries to separate
   * current paragraph with Enter key press in HTMLEditor or something.
   *
   * @param aPrincipal          Set subject principal if it may be called by
   *                            JS.  If set to nullptr, will be treated as
   *                            called by system.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  InsertParagraphSeparatorAsAction(nsIPrincipal* aPrincipal = nullptr);

  enum class InsertElementOption {
    // Delete selection if set, otherwise, insert aElement at start or end of
    // selection.
    DeleteSelection,
    // Whether split all inline ancestors or not.
    SplitAncestorInlineElements,
  };
  using InsertElementOptions = EnumSet<InsertElementOption>;
  MOZ_CAN_RUN_SCRIPT nsresult InsertElementAtSelectionAsAction(
      Element* aElement, const InsertElementOptions aOptions,
      nsIPrincipal* aPrincipal = nullptr);

  MOZ_CAN_RUN_SCRIPT nsresult InsertLinkAroundSelectionAsAction(
      Element* aAnchorElement, nsIPrincipal* aPrincipal = nullptr);

  /**
   * CreateElementWithDefaults() creates new element whose name is
   * aTagName with some default attributes are set.  Note that this is a
   * public utility method.  I.e., just creates element, not insert it
   * into the DOM tree.
   * NOTE: This is available for internal use too since this does not change
   *       the DOM tree nor undo transactions, and does not refer Selection,
   *       etc.
   *
   * @param aTagName            The new element's tag name.  If the name is
   *                            one of "href", "anchor" or "namedanchor",
   *                            this creates an <a> element.
   * @return                    Newly created element.
   */

  MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> CreateElementWithDefaults(
      const nsAtom& aTagName);

  /**
   * Indent or outdent content around Selection.
   *
   * @param aPrincipal          Set subject principal if it may be called by
   *                            JS.  If set to nullptr, will be treated as
   *                            called by system.
   */

  MOZ_CAN_RUN_SCRIPT nsresult
  IndentAsAction(nsIPrincipal* aPrincipal = nullptr);
  MOZ_CAN_RUN_SCRIPT nsresult
  OutdentAsAction(nsIPrincipal* aPrincipal = nullptr);

  /**
   * The Document.execCommand("formatBlock") handler.
   *
   * @param aParagraphFormat    Must not be an empty string, and the value must
   *                            be one of address, article, aside, blockquote,
   *                            div, footer, h1, h2, h3, h4, h5, h6, header,
   *                            hgroup, main, nav, p, pre, selection, dt or dd.
   */

  MOZ_CAN_RUN_SCRIPT nsresult FormatBlockAsAction(
      const nsAString& aParagraphFormat, nsIPrincipal* aPrincipal = nullptr);

  /**
   * The cmd_paragraphState command handler.
   *
   * @param aParagraphFormat    Can be empty string.  If this is empty string,
   *                            this removes ancestor format elements.
   *                            Otherwise, the value must be one of p, pre,
   *                            h1, h2, h3, h4, h5, h6, address, dt or dl.
   */

  MOZ_CAN_RUN_SCRIPT nsresult SetParagraphStateAsAction(
      const nsAString& aParagraphFormat, nsIPrincipal* aPrincipal = nullptr);

  MOZ_CAN_RUN_SCRIPT nsresult AlignAsAction(const nsAString& aAlignType,
                                            nsIPrincipal* aPrincipal = nullptr);

  MOZ_CAN_RUN_SCRIPT nsresult RemoveListAsAction(
      const nsAString& aListType, nsIPrincipal* aPrincipal = nullptr);

  /**
   * MakeOrChangeListAsAction() makes selected hard lines list element(s).
   *
   * @param aListElementTagName         The new list element tag name.  Must be
   *                                    nsGkAtoms::ul, nsGkAtoms::ol or
   *                                    nsGkAtoms::dl.
   * @param aBulletType                 If this is not empty string, it's set
   *                                    to `type` attribute of new list item
   *                                    elements.  Otherwise, existing `type`
   *                                    attributes will be removed.
   * @param aSelectAllOfCurrentList     Yes if this should treat all of
   *                                    ancestor list element at selection.
   */

  enum class SelectAllOfCurrentList { Yes, No };
  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MakeOrChangeListAsAction(
      const nsStaticAtom& aListElementTagName, const nsAString& aBulletType,
      SelectAllOfCurrentList aSelectAllOfCurrentList,
      nsIPrincipal* aPrincipal = nullptr);

  /**
   * If aTargetElement is a resizer, start to drag the resizer.  Otherwise, if
   * aTargetElement is the grabber, start to handle drag gester on it.
   *
   * @param aMouseDownEvent     A `mousedown` event fired on aTargetElement.
   * @param aEventTargetElement The target element being pressed.  This must
   *                            be same as explicit original event target of
   *                            aMouseDownEvent.
   */

  MOZ_CAN_RUN_SCRIPT nsresult StartToDragResizerOrHandleDragGestureOnGrabber(
      dom::MouseEvent& aMouseDownEvent, Element& aEventTargetElement);

  /**
   * If the editor is handling dragging a resizer, handling drag gesture on
   * the grabber or dragging the grabber, this finalize it.  Otherwise,
   * does nothing.
   *
   * @param aClientPoint    The final point of the drag.
   */

  MOZ_CAN_RUN_SCRIPT nsresult
  StopDraggingResizerOrGrabberAt(const CSSIntPoint& aClientPoint);

  /**
   * If the editor is handling dragging a resizer, handling drag gesture to
   * start dragging the grabber or dragging the grabber, this method updates
   * it's position.
   *
   * @param aClientPoint    The new point of the drag.
   */

  MOZ_CAN_RUN_SCRIPT nsresult
  UpdateResizerOrGrabberPositionTo(const CSSIntPoint& aClientPoint);

  /**
   * IsCSSEnabled() returns true if this editor treats styles with style
   * attribute of HTML elements.  Otherwise, if this editor treats all styles
   * with "font style elements" like <b>, <i>, etc, and <blockquote> to indent,
   * align attribute to align contents, returns false.
   */

  bool IsCSSEnabled() const { return mIsCSSPrefChecked; }

  /**
   * Enable/disable object resizers for <img> elements, <table> elements,
   * absolute positioned elements (required absolute position editor enabled).
   */

  MOZ_CAN_RUN_SCRIPT void EnableObjectResizer(bool aEnable) {
    if (mIsObjectResizingEnabled == aEnable) {
      return;
    }

    AutoEditActionDataSetter editActionData(
        *this, EditAction::eEnableOrDisableResizer);
    if (NS_WARN_IF(!editActionData.CanHandle())) {
      return;
    }

    mIsObjectResizingEnabled = aEnable;
    RefreshEditingUI();
  }
  bool IsObjectResizerEnabled() const { return mIsObjectResizingEnabled; }

  Element* GetResizerTarget() const { return mResizedObject; }

  /**
   * Enable/disable inline table editor, e.g., adding new row or column,
   * removing existing row or column.
   */

  MOZ_CAN_RUN_SCRIPT void EnableInlineTableEditor(bool aEnable) {
    if (mIsInlineTableEditingEnabled == aEnable) {
      return;
    }

    AutoEditActionDataSetter editActionData(
        *this, EditAction::eEnableOrDisableInlineTableEditingUI);
    if (NS_WARN_IF(!editActionData.CanHandle())) {
      return;
    }

    mIsInlineTableEditingEnabled = aEnable;
    RefreshEditingUI();
  }
  bool IsInlineTableEditorEnabled() const {
    return mIsInlineTableEditingEnabled;
  }

  /**
   * Enable/disable absolute position editor, resizing absolute positioned
   * elements (required object resizers enabled) or positioning them with
   * dragging grabber.
   */

  MOZ_CAN_RUN_SCRIPT void EnableAbsolutePositionEditor(bool aEnable) {
    if (mIsAbsolutelyPositioningEnabled == aEnable) {
      return;
    }

    AutoEditActionDataSetter editActionData(
        *this, EditAction::eEnableOrDisableAbsolutePositionEditor);
    if (NS_WARN_IF(!editActionData.CanHandle())) {
      return;
    }

    mIsAbsolutelyPositioningEnabled = aEnable;
    RefreshEditingUI();
  }
  bool IsAbsolutePositionEditorEnabled() const {
    return mIsAbsolutelyPositioningEnabled;
  }

  /**
   * returns the deepest absolutely positioned container of the selection
   * if it exists or null.
   */

  MOZ_CAN_RUN_SCRIPT already_AddRefed<Element>
  GetAbsolutelyPositionedSelectionContainer() const;

  Element* GetPositionedElement() const { return mAbsolutelyPositionedObject; }

  /**
   * extracts the selection from the normal flow of the document and
   * positions it.
   *
   * @param aEnabled [IN] true to absolutely position the selection,
   *                      false to put it back in the normal flow
   * @param aPrincipal          Set subject principal if it may be called by
   *                            JS.  If set to nullptr, will be treated as
   *                            called by system.
   */

  MOZ_CAN_RUN_SCRIPT nsresult SetSelectionToAbsoluteOrStaticAsAction(
      bool aEnabled, nsIPrincipal* aPrincipal = nullptr);

  /**
   * returns the absolute z-index of a positioned element. Never returns 'auto'
   * @return         the z-index of the element
   * @param aElement [IN] the element.
   */

  MOZ_CAN_RUN_SCRIPT int32_t GetZIndex(Element& aElement);

  /**
   * adds aChange to the z-index of the currently positioned element.
   *
   * @param aChange [IN] relative change to apply to current z-index
   * @param aPrincipal          Set subject principal if it may be called by
   *                            JS.  If set to nullptr, will be treated as
   *                            called by system.
   */

  MOZ_CAN_RUN_SCRIPT nsresult
  AddZIndexAsAction(int32_t aChange, nsIPrincipal* aPrincipal = nullptr);

  MOZ_CAN_RUN_SCRIPT nsresult SetBackgroundColorAsAction(
      const nsAString& aColor, nsIPrincipal* aPrincipal = nullptr);

  /**
   * SetInlinePropertyAsAction() sets a property which changes inline style of
   * text.  E.g., bold, italic, super and sub.
   * This automatically removes exclusive style, however, treats all changes
   * as a transaction.
   *
   * @param aPrincipal          Set subject principal if it may be called by
   *                            JS.  If set to nullptr, will be treated as
   *                            called by system.
   */

  MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertyAsAction(
      nsStaticAtom& aProperty, nsStaticAtom* aAttribute,
      const nsAString& aValue, nsIPrincipal* aPrincipal = nullptr);

  /**
   * GetInlineProperty() gets aggregate properties of the current selection.
   * All object in the current selection are scanned and their attributes are
   * represented in a list of Property object.
   * TODO: Make this return Result<Something> instead of bool out arguments.
   *
   * @param aHTMLProperty   the property to get on the selection
   * @param aAttribute      the attribute of the property, if applicable.
   *                        May be null.
   *                        Example: aHTMLProperty=nsGkAtoms::font,
   *                            aAttribute=nsGkAtoms::color
   * @param aValue          if aAttribute is not null, the value of the
   *                        attribute. May be null.
   *                        Example: aHTMLProperty=nsGkAtoms::font,
   *                            aAttribute=nsGkAtoms::color,
   *                            aValue="0x00FFFF"
   * @param aFirst          [OUT] true if the first text node in the
   *                              selection has the property
   * @param aAny            [OUT] true if any of the text nodes in the
   *                              selection have the property
   * @param aAll            [OUT] true if all of the text nodes in the
   *                              selection have the property
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlineProperty(
      nsStaticAtom& aHTMLProperty, nsAtom* aAttribute, const nsAString& aValue,
      bool* aFirst, bool* aAny, bool* aAll) const;

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlinePropertyWithAttrValue(
      nsStaticAtom& aHTMLProperty, nsAtom* aAttribute, const nsAString& aValue,
      bool* aFirst, bool* aAny, bool* aAll, nsAString& outValue);

  /**
   * RemoveInlinePropertyAsAction() removes a property which changes inline
   * style of text.  E.g., bold, italic, super and sub.
   *
   * @param aHTMLProperty   Tag name whcih represents the inline style you want
   *                        to remove.  E.g., nsGkAtoms::strong, nsGkAtoms::b,
   *                        etc.  If nsGkAtoms::href, <a> element which has
   *                        href attribute will be removed.
   *                        If nsGkAtoms::name, <a> element which has non-empty
   *                        name attribute will be removed.
   * @param aAttribute  If aHTMLProperty is nsGkAtoms::font, aAttribute should
   *                    be nsGkAtoms::fase, nsGkAtoms::size, nsGkAtoms::color
   *                    or nsGkAtoms::bgcolor.  Otherwise, set nullptr.
   *                    Must not use nsGkAtoms::_empty here.
   * @param aPrincipal  Set subject principal if it may be called by JS.  If
   *                    set to nullptr, will be treated as called by system.
   */

  MOZ_CAN_RUN_SCRIPT nsresult RemoveInlinePropertyAsAction(
      nsStaticAtom& aHTMLProperty, nsStaticAtom* aAttribute,
      nsIPrincipal* aPrincipal = nullptr);

  MOZ_CAN_RUN_SCRIPT nsresult
  RemoveAllInlinePropertiesAsAction(nsIPrincipal* aPrincipal = nullptr);

  MOZ_CAN_RUN_SCRIPT nsresult
  IncreaseFontSizeAsAction(nsIPrincipal* aPrincipal = nullptr);

  MOZ_CAN_RUN_SCRIPT nsresult
  DecreaseFontSizeAsAction(nsIPrincipal* aPrincipal = nullptr);

  /**
   * GetFontColorState() returns foreground color information in first
   * range of Selection.
   * If first range of Selection is collapsed and there is a cache of style for
   * new text, aIsMixed is set to false and aColor is set to the cached color.
   * If first range of Selection is collapsed and there is no cached color,
   * this returns the color of the node, aIsMixed is set to false and aColor is
   * set to the color.
   * If first range of Selection is not collapsed, this collects colors of
   * each node in the range.  If there are two or more colors, aIsMixed is set
   * to true and aColor is truncated.  If only one color is set to all of the
   * range, aIsMixed is set to false and aColor is set to the color.
   * If there is no Selection ranges, aIsMixed is set to false and aColor is
   * truncated.
   *
   * @param aIsMixed            Must not be nullptr.  This is set to true
   *                            if there is two or more colors in first
   *                            range of Selection.
   * @param aColor              Returns the color if only one color is set to
   *                            all of first range in Selection.  Otherwise,
   *                            returns empty string.
   * @return                    Returns error only when illegal cases, e.g.,
   *                            Selection instance has gone, first range
   *                            Selection is broken.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  GetFontColorState(bool* aIsMixed, nsAString& aColor);

  /**
   * Detach aComposerCommandsUpdater from this.
   */

  void Detach(const ComposerCommandsUpdater& aComposerCommandsUpdater);

  nsStaticAtom& DefaultParagraphSeparatorTagName() const {
    return HTMLEditor::ToParagraphSeparatorTagName(mDefaultParagraphSeparator);
  }
  ParagraphSeparator GetDefaultParagraphSeparator() const {
    return mDefaultParagraphSeparator;
  }
  void SetDefaultParagraphSeparator(ParagraphSeparator aSep) {
    mDefaultParagraphSeparator = aSep;
  }
  static nsStaticAtom& ToParagraphSeparatorTagName(
      ParagraphSeparator aSeparator) {
    switch (aSeparator) {
      case ParagraphSeparator::div:
        return *nsGkAtoms::div;
      case ParagraphSeparator::p:
        return *nsGkAtoms::p;
      case ParagraphSeparator::br:
        return *nsGkAtoms::br;
      default:
        MOZ_ASSERT_UNREACHABLE("New paragraph separator isn't handled here");
        return *nsGkAtoms::div;
    }
  }

  /**
   * Modifies the table containing the selection according to the
   * activation of an inline table editing UI element
   * @param aUIAnonymousElement [IN] the inline table editing UI element
   */

  MOZ_CAN_RUN_SCRIPT nsresult
  DoInlineTableEditingAction(const Element& aUIAnonymousElement);

  /**
   * GetInclusiveAncestorByTagName() looks for an element node whose name
   * matches aTagName from aNode or anchor node of Selection to <body> element.
   *
   * @param aTagName        The tag name which you want to look for.
   *                        Must not be nsGkAtoms::_empty.
   *                        If nsGkAtoms::list, the result may be <ul>, <ol> or
   *                        <dl> element.
   *                        If nsGkAtoms::td, the result may be <td> or <th>.
   *                        If nsGkAtoms::href, the result may be <a> element
   *                        which has "href" attribute with non-empty value.
   *                        If nsGkAtoms::anchor, the result may be <a> which
   *                        has "name" attribute with non-empty value.
   * @param aContent        Start node to look for the result.
   * @return                If an element which matches aTagName, returns
   *                        an Element.  Otherwise, nullptr.
   */

  Element* GetInclusiveAncestorByTagName(const nsStaticAtom& aTagName,
                                         nsIContent& aContent) const;

  /**
   * Compute editing host for aContent.  If this editor isn't active in the DOM
   * window, this returns nullptr.
   */

  enum class LimitInBodyElement { No, Yes };
  [[nodiscard]] Element* ComputeEditingHost(
      const nsIContent& aContent,
      LimitInBodyElement aLimitInBodyElement = LimitInBodyElement::Yes) const {
    return ComputeEditingHostInternal(&aContent, aLimitInBodyElement);
  }

  /**
   * Compute editing host for the focus node of the Selection.  If this editor
   * isn't active in the DOM window, this returns nullptr.
   */

  [[nodiscard]] Element* ComputeEditingHost(
      LimitInBodyElement aLimitInBodyElement = LimitInBodyElement::Yes) const {
    return ComputeEditingHostInternal(nullptr, aLimitInBodyElement);
  }

  /**
   * Return true if this editor was notified of focus, but has not been notified
   * of the blur.
   */

  [[nodiscard]] bool HasFocus() const { return mHasFocus; }

  /**
   * Return true if this editor is in the designMode.
   */

  [[nodiscard]] bool IsInDesignMode() const { return mIsInDesignMode; }

  /**
   * Return true if entire the document is editable (although the document
   * may have non-editable nodes, e.g.,
   * <body contenteditable><div contenteditable="false"></div></body>
   */

  bool EntireDocumentIsEditable() const;

  /**
   * Basically, this always returns true if we're for `contenteditable` or
   * `designMode` editor in web apps.  However, e.g., Composer of SeaMonkey
   * can make the editor not tabbable.
   */

  bool IsTabbable() const { return IsInteractionAllowed(); }

  /**
   * NotifyEditingHostMaybeChanged() is called when new element becomes
   * contenteditable when the document already had contenteditable elements.
   */

  void NotifyEditingHostMaybeChanged();

  /** Insert a string as quoted text
   * (whose representation is dependant on the editor type),
   * replacing the selected text (if any).
   *
   * @param aQuotedText    The actual text to be quoted
   * @parem aNodeInserted  Return the node which was inserted.
   */

  MOZ_CAN_RUN_SCRIPT  // USED_BY_COMM_CENTRAL
      nsresult
      InsertAsQuotation(const nsAString& aQuotedText, nsINode** aNodeInserted);

  MOZ_CAN_RUN_SCRIPT nsresult InsertHTMLAsAction(
      const nsAString& aInString, nsIPrincipal* aPrincipal = nullptr);

  /**
   * Refresh positions of resizers.  If you change size of target of resizers,
   * you need to refresh position of resizers with calling this.
   */

  MOZ_CAN_RUN_SCRIPT nsresult RefreshResizers();

  bool IsWrapHackEnabled() const {
    return (mFlags & nsIEditor::eEditorEnableWrapHackMask) != 0;
  }

  /**
   * Return true if this is in the plaintext mail composer mode of
   * Thunderbird or something.
   * NOTE: This is different from contenteditable="plaintext-only"
   */

  bool IsPlaintextMailComposer() const {
    const bool isPlaintextMode =
        (mFlags & nsIEditor::eEditorPlaintextMask) != 0;
    MOZ_ASSERT_IF(IsTextEditor(), isPlaintextMode);
    return isPlaintextMode;
  }

 protected:  // May be called by friends.
  /****************************************************************************
   * Some friend classes are allowed to call the following protected methods.
   * However, those methods won't prepare caches of some objects which are
   * necessary for them.  So, if you call them from friend classes, you need
   * to make sure that AutoEditActionDataSetter is created.
   ****************************************************************************/


  enum class LineBreakType : bool {
    BRElement,  // <br>
    Linefeed,   // Preformatted linefeed
  };
  friend std::ostream& operator<<(std::ostream& aStream,
                                  const LineBreakType aLineBreakType) {
    switch (aLineBreakType) {
      case LineBreakType::BRElement:
        return aStream << "LineBreakType::BRElement";
      case LineBreakType::Linefeed:
        return aStream << "LineBreakType::BRElement";
    }
    MOZ_ASSERT_UNREACHABLE("Invalid LineBreakType");
    return aStream;
  }

  /**
   * Return preferred line break when you insert a line break in aNode (if
   * aNode is a Text node, this assumes that line break will be inserted to
   * its parent element).
   *
   * @param aNode           The node where you want to insert a line break.
   *                        This should be a inclusive descendant of
   *                        aEditingHost because if it's not connected, we can
   *                        not refer the proper style information.
   * @param aEditingHost    The editing host.
   */

  Maybe<LineBreakType> GetPreferredLineBreakType(
      const nsINode& aNode, const Element& aEditingHost) const;

  /**
   * InsertLineBreak() creates a <br> element or a Text node which has only
   * preformatted linefeed and inserts it at aPointToInsert.
   *
   * @param aWithTransaction    Whether the inserting is new element is undoable
   *                            or not.  WithTransaction::No is useful only when
   *                            the new element is inserted into a new element
   *                            which has not been connected yet.
   * @param aLineBreakType      Whether a <br> element or a linefeed should be
   *                            used.
   * @param aPointToInsert      The DOM point where a <br> element or a Text
   *                            node should be inserted.
   * @param aSelect             If eNone, returns a point to put caret which is
   *                            suggested by InsertNodeTransaction.
   *                            If eNext, returns a point after the new <br>
   *                            element.
   *                            If ePrevious, returns a point at the new <br>
   *                            element.
   * @return                    The new <br> or Text node and suggesting point
   *                            to put caret with respecting aSelect.
   */

  MOZ_CAN_RUN_SCRIPT Result<CreateLineBreakResult, nsresult> InsertLineBreak(
      WithTransaction aWithTransaction, LineBreakType aLineBreakType,
      const EditorDOMPoint& aPointToInsert, EDirection aSelect = eNone);

  /**
   * Delete text in the range in aTextNode.  If aTextNode is not editable, this
   * does nothing.
   *
   * @param aTextNode           The text node which should be modified.
   * @param aOffset             Start offset of removing text in aTextNode.
   * @param aLength             Length of removing text.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
  DeleteTextWithTransaction(dom::Text& aTextNode, uint32_t aOffset,
                            uint32_t aLength);

  /**
   * Replace text in the range with aStringToInsert.  If there is a DOM range
   * exactly same as the replacing range, it'll be collapsed to
   * {aTextNode, aOffset} because of the order of deletion and insertion.
   * Therefore, the callers may need to handle `Selection` even when callers
   * do not want to update `Selection`.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertTextResult, nsresult>
  ReplaceTextWithTransaction(dom::Text& aTextNode, uint32_t aOffset,
                             uint32_t aLength,
                             const nsAString& aStringToInsert);

  /**
   * Insert aStringToInsert to aPointToInsert.  If the point is not editable,
   * this returns error.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertTextResult, nsresult>
  InsertTextWithTransaction(Document& aDocument,
                            const nsAString& aStringToInsert,
                            const EditorDOMPoint& aPointToInsert,
                            InsertTextTo aInsertTextTo) final;

  /**
   * CopyLastEditableChildStyles() clones inline container elements into
   * aPreviousBlock to aNewBlock to keep using same style in it.
   *
   * @param aPreviousBlock      The previous block element.  All inline
   *                            elements which are last sibling of each level
   *                            are cloned to aNewBlock.
   * @param aNewBlock           New block container element.  All children of
   *                            this is deleted first.
   * @param aEditingHost        The editing host.
   * @return                    If succeeded, returns a suggesting point to put
   *                            caret.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
  CopyLastEditableChildStylesWithTransaction(Element& aPreviousBlock,
                                             Element& aNewBlock,
                                             const Element& aEditingHost);

  /**
   * RemoveBlockContainerWithTransaction() removes aElement from the DOM tree
   * but moves its all children to its parent node and if its parent needs <br>
   * element to have at least one line-height, this inserts <br> element
   * automatically.
   *
   * @param aElement            Block element to be removed.
   * @return                    If succeeded, returns a suggesting point to put
   *                            caret.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
  RemoveBlockContainerWithTransaction(Element& aElement);

  MOZ_CAN_RUN_SCRIPT nsresult RemoveAttributeOrEquivalent(
      Element* aElement, nsAtom* aAttribute, bool aSuppressTransaction) final;
  MOZ_CAN_RUN_SCRIPT nsresult SetAttributeOrEquivalent(
      Element* aElement, nsAtom* aAttribute, const nsAString& aValue,
      bool aSuppressTransaction) final;
  using EditorBase::RemoveAttributeOrEquivalent;
  using EditorBase::SetAttributeOrEquivalent;

  /**
   * Returns container element of ranges in Selection.  If Selection is
   * collapsed, returns focus container node (or its parent element).
   * If Selection selects only one element node, returns the element node.
   * If Selection is only one range, returns common ancestor of the range.
   * XXX If there are two or more Selection ranges, this returns parent node
   *     of start container of a range which starts with different node from
   *     start container of the first range.
   */

  Element* GetSelectionContainerElement() const;

  /**
   * DeleteTableCellContentsWithTransaction() removes any contents in cell
   * elements.  If two or more cell elements are selected, this removes
   * all selected cells' contents.  Otherwise, this removes contents of
   * a cell which contains first selection range.  This does not return
   * error even if selection is not in cell element, just does nothing.
   */

  MOZ_CAN_RUN_SCRIPT nsresult DeleteTableCellContentsWithTransaction();

  /**
   * extracts an element from the normal flow of the document and
   * positions it, and puts it back in the normal flow.
   * @param aElement [IN] the element
   * @param aEnabled [IN] true to absolutely position the element,
   *                      false to put it back in the normal flow
   */

  MOZ_CAN_RUN_SCRIPT nsresult SetPositionToAbsoluteOrStatic(Element& aElement,
                                                            bool aEnabled);

  /**
   * adds aChange to the z-index of an arbitrary element.
   * @param aElement    [IN] the element
   * @param aChange     [IN] relative change to apply to current z-index of
   *                    the element
   * @return            The new z-index of the element
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<int32_t, nsresult>
  AddZIndexWithTransaction(nsStyledElement& aStyledElement, int32_t aChange);

  /**
   * Join together adjacent editable text nodes in the range except preformatted
   * linefeed only nodes.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  CollapseAdjacentTextNodes(nsRange& aRange);

  static dom::Element* GetLinkElement(nsINode* aNode);

  /**
   * Helper routines for font size changing.
   */

  enum class FontSize { incr, decr };
  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
  SetFontSizeOnTextNode(Text& aTextNode, uint32_t aStartOffset,
                        uint32_t aEndOffset, FontSize aIncrementOrDecrement);

  enum class SplitAtEdges {
    // SplitNodeDeepWithTransaction() won't split container element
    // nodes at their edges.  I.e., when split point is start or end of
    // container, it won't be split.
    eDoNotCreateEmptyContainer,
    // SplitNodeDeepWithTransaction() always splits containers even
    // if the split point is at edge of a container.  E.g., if split point is
    // start of an inline element, empty inline element is created as a new left
    // node.
    eAllowToCreateEmptyContainer,
  };

  /**
   * SplitAncestorStyledInlineElementsAtRangeEdges() splits all ancestor inline
   * elements in the block at aRange if given style matches with some of them.
   *
   * @param aRange              Ancestor inline elements of the start and end
   *                            boundaries will be split.
   * @param aStyle              The style which you want to split.
   *                            RemoveAllStyles instance is allowed to split any
   *                            inline elements.
   * @param aSplitAtEdges       Whether this should split elements at start or
   *                            end of inline elements or not.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffResult, nsresult>
  SplitAncestorStyledInlineElementsAtRangeEdges(const EditorDOMRange& aRange,
                                                const EditorInlineStyle& aStyle,
                                                SplitAtEdges aSplitAtEdges);

  /**
   * SplitAncestorStyledInlineElementsAt() splits ancestor inline elements at
   * aPointToSplit if specified style matches with them.
   *
   * @param aPointToSplit       The point to split style at.
   * @param aStyle              The style which you want to split.
   *                            RemoveAllStyles instance is allowed to split any
   *                            inline elements.
   * @param aSplitAtEdges       Whether this should split elements at start or
   *                            end of inline elements or not.
   * @return                    The result of SplitNodeDeepWithTransaction()
   *                            with topmost split element.  If this didn't
   *                            find inline elements to be split, Handled()
   *                            returns false.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
  SplitAncestorStyledInlineElementsAt(const EditorDOMPoint& aPointToSplit,
                                      const EditorInlineStyle& aStyle,
                                      SplitAtEdges aSplitAtEdges);

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlinePropertyBase(
      const EditorInlineStyle& aStyle, const nsAString* aValue, bool* aFirst,
      bool* aAny, bool* aAll, nsAString* outValue) const;

  /**
   * ClearStyleAt() splits parent elements to remove the specified style.
   * If this splits some parent elements at near their start or end, such
   * empty elements will be removed.  Then, remove the specified style
   * from the point and returns DOM point to put caret.
   *
   * @param aPoint      The point to clear style at.
   * @param aStyleToRemove   The style which you want to clear.
   * @param aSpecifiedStyle  Whether the class and style attributes should
   *                         be preserved or discarded.
   * @param aEditingHost     The editing host.
   * @return            A candidate position to put caret.  If there is
   *                    AutoTransactionsConserveSelection instances, this stops
   *                    suggesting caret point only in some cases.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
  ClearStyleAt(const EditorDOMPoint& aPoint,
               const EditorInlineStyle& aStyleToRemove,
               SpecifiedStyle aSpecifiedStyle, const Element& aEditingHost);

  MOZ_CAN_RUN_SCRIPT nsresult SetPositionToAbsolute(Element& aElement);
  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  SetPositionToStatic(Element& aElement);

  class DocumentModifiedEvent final : public Runnable {
   public:
    explicit DocumentModifiedEvent(HTMLEditor& aHTMLEditor)
        : Runnable("DocumentModifiedEvent"), mHTMLEditor(aHTMLEditor) {}

    MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() {
      Unused << MOZ_KnownLive(mHTMLEditor)->OnModifyDocument(*this);
      return NS_OK;
    }

    const nsTArray<EditorDOMPointInText>& NewInvisibleWhiteSpacesRef() const {
      return mNewInvisibleWhiteSpaces;
    }

    void MaybeAppendNewInvisibleWhiteSpace(
        const nsIContent* aContentWillBeRemoved);

   private:
    ~DocumentModifiedEvent() = default;

    const OwningNonNull<HTMLEditor> mHTMLEditor;
    nsTArray<EditorDOMPointInText> mNewInvisibleWhiteSpaces;
  };

  /**
   * OnModifyDocument() is called when the editor is changed.  This should
   * be called only by DocumentModifiedEvent when AutoEditActionDataSetter
   * instance is in the stack.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  OnModifyDocument(const DocumentModifiedEvent& aRunner);

  /**
   * DoSplitNode() inserts aNewNode and moves all content before or after
   * aStartOfRightNode to aNewNode.
   *
   * @param aStartOfRightNode   The point to split.  The container will keep
   *                            having following or previous content of this.
   * @param aNewNode            The new node called.  The previous or following
   *                            content of aStartOfRightNode will be moved into
   *                            this node.
   */

  MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult> DoSplitNode(
      const EditorDOMPoint& aStartOfRightNode, nsIContent& aNewNode);

  /**
   * DoJoinNodes() merges contents in aContentToRemove to aContentToKeep and
   * remove aContentToRemove from the DOM tree.  aContentToRemove and
   * aContentToKeep must have same parent.  Additionally, if one of
   * aContentToRemove or aContentToKeep is a text node, the other must be a
   * text node.
   *
   * @param aContentToKeep    The node that will remain after the join.
   * @param aContentToRemove  The node that will be joined with aContentToKeep.
   *                          There is no requirement that the two nodes be of
   *                          the same type.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  DoJoinNodes(nsIContent& aContentToKeep, nsIContent& aContentToRemove);

  /**
   * Called when JoinNodesTransaction::DoTransaction() did its transaction.
   * Note that this is not called when undoing nor redoing.
   *
   * @param aTransaction        The transaction which did join nodes.
   * @param aDoJoinNodesResult  Result of the doing join nodes.
   */

  MOZ_CAN_RUN_SCRIPT void DidJoinNodesTransaction(
      const JoinNodesTransaction& aTransaction, nsresult aDoJoinNodesResult);

 protected:  // edit sub-action handler
  /**
   * CanHandleHTMLEditSubAction() checks whether there is at least one
   * selection range or not, and whether the first range is editable.
   * If it's not editable, `Canceled()` of the result returns true.
   * If `Selection` is in odd situation, returns an error.
   *
   * XXX I think that `IsSelectionEditable()` is better name, but it's already
   *     in `EditorBase`...
   */

  enum class CheckSelectionInReplacedElement { Yes, OnlyWhenNotInSameNode };
  Result<EditActionResult, nsresult> CanHandleHTMLEditSubAction(
      CheckSelectionInReplacedElement aCheckSelectionInReplacedElement =
          CheckSelectionInReplacedElement::Yes) const;

  /**
   * EnsureCaretNotAfterInvisibleBRElement() makes sure that caret is NOT after
   * padding `<br>` element for preventing insertion after padding `<br>`
   * element at empty last line.
   * NOTE: This method should be called only when `Selection` is collapsed
   *       because `Selection` is a pain to work with when not collapsed.
   *       (no good way to extend start or end of selection), so we need to
   *       ignore those types of selections.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  EnsureCaretNotAfterInvisibleBRElement(const Element& aEditingHost);

  /**
   * MaybeCreatePaddingBRElementForEmptyEditor() creates padding <br> element
   * for empty editor if there is no children.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  MaybeCreatePaddingBRElementForEmptyEditor();

  /**
   * EnsureNoPaddingBRElementForEmptyEditor() removes padding <br> element
   * for empty editor if there is.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  EnsureNoPaddingBRElementForEmptyEditor();

  /**
   * ReflectPaddingBRElementForEmptyEditor() scans the tree from the root
   * element and sets mPaddingBRElementForEmptyEditor if exists, or otherwise
   * nullptr.  Can be used to manage undo/redo.
   */

  [[nodiscard]] nsresult ReflectPaddingBRElementForEmptyEditor();

  /**
   * PrepareInlineStylesForCaret() consider inline styles from top level edit
   * sub-action and setting it to `mPendingStylesToApplyToNewContent` and clear
   * inline style cache if necessary.
   * NOTE: This method should be called only when `Selection` is collapsed.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult PrepareInlineStylesForCaret();

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
  HandleInsertText(EditSubAction aEditSubAction,
                   const nsAString& aInsertionString,
                   SelectionHandling aSelectionHandling) final;

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertDroppedDataTransferAsAction(
      AutoEditActionDataSetter& aEditActionData, DataTransfer& aDataTransfer,
      const EditorDOMPoint& aDroppedAt, nsIPrincipal* aSourcePrincipal) final;

  /**
   * GetInlineStyles() retrieves the style of aElement and modifies each item of
   * aPendingStyleCacheArray.  This might cause flushing layout at retrieving
   * computed values of CSS properties.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlineStyles(
      Element& aElement, AutoPendingStyleCacheArray& aPendingStyleCacheArray);

  /**
   * CacheInlineStyles() caches style of aElement into mCachedPendingStyles of
   * TopLevelEditSubAction.  This may cause flushing layout at retrieving
   * computed value of CSS properties.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  CacheInlineStyles(Element& aElement);

  /**
   * ReapplyCachedStyles() restores some styles which are disappeared during
   * handling edit action and it should be restored.  This may cause flushing
   * layout at retrieving computed value of CSS properties.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ReapplyCachedStyles();

  /**
   * CreateStyleForInsertText() sets CSS properties which are stored in
   * PendingStyles to proper element node.
   *
   * @param aPointToInsertText  The point to insert text.
   * @param aEditingHost        The editing host.
   * @return                    A suggest point to put caret or unset point.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
  CreateStyleForInsertText(const EditorDOMPoint& aPointToInsertText,
                           const Element& aEditingHost);

  /**
   * GetMostDistantAncestorMailCiteElement() returns most-ancestor mail cite
   * element. "mail cite element" is <pre> element when it's in plaintext editor
   * mode or an element with which calling HTMLEditUtils::IsMailCite() returns
   * true.
   *
   * @param aNode       The start node to look for parent mail cite elements.
   */

  Element* GetMostDistantAncestorMailCiteElement(const nsINode& aNode) const;

  /**
   * HandleInsertParagraphInMailCiteElement() splits aMailCiteElement at
   * aPointToSplit.
   *
   * @param aMailCiteElement    The mail-cite element which should be split.
   * @param aPointToSplit       The point to split.
   * @return                    Candidate caret position where is at inserted
   *                            <br> element into the split point.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
  HandleInsertParagraphInMailCiteElement(Element& aMailCiteElement,
                                         const EditorDOMPoint& aPointToSplit);

  /**
   * HandleInsertBRElement() inserts a <br> element into aPointToBreak.
   * This may split container elements at the point and/or may move following
   * <br> element to immediately after the new <br> element if necessary.
   *
   * @param aPointToBreak       The point where new <br> element will be
   *                            inserted before.
   * @param aEditingHost        Current active editing host.
   * @return                    If succeeded, returns new <br> element and
   *                            candidate caret point.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
  HandleInsertBRElement(const EditorDOMPoint& aPointToBreak,
                        const Element& aEditingHost);

  /**
   * HandleInsertLinefeed() inserts a linefeed character into aPointToBreak.
   *
   * @param aPointToBreak       The point where new linefeed character will be
   *                            inserted before.
   * @param aEditingHost        Current active editing host.
   * @return                    A suggest point to put caret.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
  HandleInsertLinefeed(const EditorDOMPoint& aPointToBreak,
                       const Element& aEditingHost);

  /**
   * Splits inclusive inline ancestors at both start and end of aRangeItem.  If
   * this splits at every point, this modifies aRangeItem to point each split
   * point (typically, at right node).
   *
   * @param aRangeItem          [in/out] One or two DOM points where should be
   *                            split.  Will be modified to split point if
   *                            they're split.
   * @param aBlockInlineCheck   [in] Whether this method considers block vs.
   *                            inline with computed style or the default style.
   * @param aEditingHost        [in] The editing host.
   * @param aAncestorLimiter    [in/optional] If specified, this stops splitting
   *                            ancestors when meets this node.
   * @return                    A suggest point to put caret if succeeded, but
   *                            it may be unset.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
  SplitInlineAncestorsAtRangeBoundaries(
      RangeItem& aRangeItem, BlockInlineCheck aBlockInlineCheck,
      const Element& aEditingHost,
      const nsIContent* aAncestorLimiter = nullptr);

  /**
   * SplitElementsAtEveryBRElement() splits before all <br> elements in
   * aMostAncestorToBeSplit.  All <br> nodes will be moved before right node
   * at splitting its parent.  Finally, this returns left node, first <br>
   * element, next left node, second <br> element... and right-most node.
   *
   * @param aMostAncestorToBeSplit      Most-ancestor element which should
   *                                    be split.
   * @param aOutArrayOfNodes            First left node, first <br> element,
   *                                    Second left node, second <br> element,
   *                                    ...right-most node.  So, all nodes
   *                                    in this list should be siblings (may be
   *                                    broken the relation by mutation event
   *                                    listener though). If first <br> element
   *                                    is first leaf node of
   *                                    aMostAncestorToBeSplit, starting from
   *                                    the first <br> element.
   * @return                            A suggest point to put caret if
   *                                    succeeded, but it may unset.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
  SplitElementsAtEveryBRElement(
      nsIContent& aMostAncestorToBeSplit,
      nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents);

  /**
   * MaybeSplitElementsAtEveryBRElement() calls SplitElementsAtEveryBRElement()
   * for each given node when this needs to do that for aEditSubAction.
   * If split a node, it in aArrayOfContents is replaced with split nodes and
   * <br> elements.
   *
   * @return                            A suggest point to put caret if
   *                                    succeeded, but it may unset.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
  MaybeSplitElementsAtEveryBRElement(
      nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
      EditSubAction aEditSubAction);

  /**
   * CreateRangeIncludingAdjuscentWhiteSpaces() creates an nsRange instance
   * which may be expanded from the given range to include adjuscent
   * white-spaces.  If this fails handling something, returns nullptr.
   */

  template <typename EditorDOMRangeType>
  already_AddRefed<nsRange> CreateRangeIncludingAdjuscentWhiteSpaces(
      const EditorDOMRangeType& aRange);
  template <typename EditorDOMPointType1, typename EditorDOMPointType2>
  already_AddRefed<nsRange> CreateRangeIncludingAdjuscentWhiteSpaces(
      const EditorDOMPointType1& aStartPoint,
      const EditorDOMPointType2& aEndPoint);

  /**
   * GetRangeExtendedToHardLineEdgesForBlockEditAction() returns an extended
   * range if aRange should be extended before handling a block level editing.
   * If aRange start and/or end point <br> or something non-editable point, they
   * should be moved to nearest text node or something where the other methods
   * easier to handle edit action.
   */

  [[nodiscard]] Result<EditorRawDOMRange, nsresult>
  GetRangeExtendedToHardLineEdgesForBlockEditAction(
      const nsRange* aRange, const Element& aEditingHost) const;

  /**
   * InitializeInsertingElement is a callback type of methods which inserts
   * an element into the DOM tree.  This is called immediately before inserting
   * aNewElement into the DOM tree.
   *
   * @param aHTMLEditor     The HTML editor which modifies the DOM tree.
   * @param aNewElement     The new element which will be or was inserted into
   *                        the DOM tree.
   * @param aPointToInsert  The position aNewElement will be or was inserted.
   */

  using InitializeInsertingElement =
      std::function<nsresult(HTMLEditor& aHTMLEditor, Element& aNewElement,
                             const EditorDOMPoint& aPointToInsert)>;
  static InitializeInsertingElement DoNothingForNewElement;
  static InitializeInsertingElement InsertNewBRElement;

  /**
   * Helper methods to implement InitializeInsertingElement.
   */

  MOZ_CAN_RUN_SCRIPT static Result<CreateElementResult, nsresult>
  AppendNewElementToInsertingElement(
      HTMLEditor& aHTMLEditor, const nsStaticAtom& aTagName,
      Element& aNewElement,
      const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
  MOZ_CAN_RUN_SCRIPT static Result<CreateElementResult, nsresult>
  AppendNewElementWithBRToInsertingElement(HTMLEditor& aHTMLEditor,
                                           const nsStaticAtom& aTagName,
                                           Element& aNewElement);

  /**
   * Create an element node whose name is aTag at before aPointToInsert.  When
   * this succeed to create an element node, this inserts the element to
   * aPointToInsert.
   *
   * @param aWithTransaction    Whether the inserting is new element is undoable
   *                            or not.  WithTransaction::No is useful only when
   *                            the new element is inserted into a new element
   *                            which has not been connected yet.
   * @param aTagName            The element name to create.
   * @param aPointToInsert      The insertion point of new element.
   *                            If this refers end of the container or after,
   *                            the transaction will append the element to the
   *                            container.
   *                            Otherwise, will insert the element before the
   *                            child node referred by this.
   *                            Note that this point will be invalid once this
   *                            method inserts the new element.
   * @param aInitializer        A function to initialize the new element before
   *                            connecting the element into the DOM tree. Note
   *                            that this should not touch outside given element
   *                            because doing it would break range updater's
   *                            result.
   * @return                    The created new element node and candidate caret
   *                            position.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
  CreateAndInsertElement(
      WithTransaction aWithTransaction, const nsAtom& aTagName,
      const EditorDOMPoint& aPointToInsert,
      const InitializeInsertingElement& aInitializer = DoNothingForNewElement);

  /**
   * Callback of CopyAttributes().
   *
   * @param aHTMLEditor   The HTML editor.
   * @param aSrcElement   The element which have the attribute.
   * @param aDestElement  The element which will have the attribute.
   * @param aNamespaceID  [in] The namespace ID of aAttrName.
   * @param aAttrName     [in] The attribute name which will be copied.
   * @param aValue        [in/out] The attribute value which will be copied.
   *                      Once updated, the new value is used.
   * @return              true if the attribute should be copied, otherwise,
   *                      false.
   */

  using AttributeFilter = std::function<bool(
      HTMLEditor& aHTMLEditor, Element& aSrcElement, Element& aDestElement,
      int32_t aNamespaceID, const nsAtom& aAttrName, nsString& aValue)>;
  static AttributeFilter CopyAllAttributes;
  static AttributeFilter CopyAllAttributesExceptId;
  static AttributeFilter CopyAllAttributesExceptDir;
  static AttributeFilter CopyAllAttributesExceptIdAndDir;

  /**
   * Copy all attributes of aSrcElement to aDestElement as-is.  Different from
   * EditorBase::CloneAttributesWithTransaction(), this does not use
   * SetAttributeOrEquivalent() nor does not clear existing attributes of
   * aDestElement.
   *
   * @param aWithTransaction    Whether recoding with transactions or not.
   * @param aDestElement        The element will have attributes.
   * @param aSrcElement         The element whose attributes will be copied.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult CopyAttributes(
      WithTransaction aWithTransaction, Element& aDestElement,
      Element& aSrcElement, const AttributeFilter& = CopyAllAttributes);

  /**
   * MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of
   * aStartOfDeepestRightNode can have an element whose tag name is aTag.
   * Otherwise, looks for an ancestor node which is or is in active editing
   * host and can have an element whose name is aTag.  If there is such
   * ancestor, its descendants are split.
   *
   * Note that this may create empty elements while splitting ancestors.
   *
   * @param aTag                        The name of element to be inserted
   *                                    after calling this method.
   * @param aStartOfDeepestRightNode    The start point of deepest right node.
   *                                    This point must be in aEditingHost.
   * @param aEditingHost                The editing host.
   * @return                            When succeeded, SplitPoint() returns
   *                                    the point to insert the element.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
  MaybeSplitAncestorsForInsertWithTransaction(
      const nsAtom& aTag, const EditorDOMPoint& aStartOfDeepestRightNode,
      const Element& aEditingHost);

  /**
   * InsertElementWithSplittingAncestorsWithTransaction() is a wrapper of
   * MaybeSplitAncestorsForInsertWithTransaction() and CreateAndInsertElement().
   * I.e., will create an element whose tag name is aTagName and split ancestors
   * if it's necessary, then, insert it.
   *
   * @param aTagName            The tag name which you want to insert new
   *                            element at aPointToInsert.
   * @param aPointToInsert      The insertion point.  New element will be
   *                            inserted before here.
   * @param aBRElementNextToSplitPoint
   *                            Whether <br> element should be deleted or
   *                            kept if and only if a <br> element follows
   *                            split point.
   * @param aEditingHost        The editing host with which we're handling it.
   * @param aInitializer        A function to initialize the new element before
   *                            connecting the element into the DOM tree. Note
   *                            that this should not touch outside given element
   *                            because doing it would break range updater's
   *                            result.
   * @return                    If succeeded, returns the new element node and
   *                            suggesting point to put caret.
   */

  enum class BRElementNextToSplitPoint { Keep, Delete };
  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
  InsertElementWithSplittingAncestorsWithTransaction(
      const nsAtom& aTagName, const EditorDOMPoint& aPointToInsert,
      BRElementNextToSplitPoint aBRElementNextToSplitPoint,
      const Element& aEditingHost,
      const InitializeInsertingElement& aInitializer = DoNothingForNewElement);

  /**
   * Split aElementToSplit at two points, before aStartOfMiddleElement and after
   * aEndOfMiddleElement.  If they are very start or very end of aBlockElement,
   * this won't create empty block.
   *
   * @param aElementToSplit         An element which will be split.
   * @param aStartOfMiddleElement   Start node of middle block element.
   * @param aEndOfMiddleElement     End node of middle block element.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
--> --------------------

--> maximum size reached

--> --------------------

100%


¤ Dauer der Verarbeitung: 0.44 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.