tor-browser

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

nsFrameSelection.h (54376B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef nsFrameSelection_h___
      8 #define nsFrameSelection_h___
      9 
     10 #include <stdint.h>
     11 
     12 #include "WordMovementType.h"
     13 #include "mozilla/Assertions.h"
     14 #include "mozilla/Attributes.h"
     15 #include "mozilla/CaretAssociationHint.h"
     16 #include "mozilla/CompactPair.h"
     17 #include "mozilla/EnumSet.h"
     18 #include "mozilla/EventForwards.h"
     19 #include "mozilla/Result.h"
     20 #include "mozilla/TextRange.h"
     21 #include "mozilla/UniquePtr.h"
     22 #include "mozilla/dom/Element.h"
     23 #include "mozilla/dom/Highlight.h"
     24 #include "mozilla/dom/Selection.h"
     25 #include "mozilla/intl/BidiEmbeddingLevel.h"
     26 #include "nsBidiPresUtils.h"
     27 #include "nsIContent.h"
     28 #include "nsIFrame.h"
     29 #include "nsISelectionController.h"
     30 #include "nsISelectionListener.h"
     31 #include "nsITableCellLayout.h"
     32 
     33 class nsRange;
     34 
     35 #define BIDI_LEVEL_UNDEFINED mozilla::intl::BidiEmbeddingLevel(0x80)
     36 
     37 //----------------------------------------------------------------------
     38 
     39 // Selection interface
     40 
     41 struct SelectionDetails {
     42  SelectionDetails()
     43      : mStart(), mEnd(), mSelectionType(mozilla::SelectionType::eInvalid) {
     44    MOZ_COUNT_CTOR(SelectionDetails);
     45  }
     46  ~SelectionDetails() {
     47    MOZ_COUNT_DTOR(SelectionDetails);
     48    // Destroy the linked list without recursion.
     49    auto next = std::move(mNext);
     50    while (next) {
     51      next = std::move(next->mNext);
     52    }
     53  }
     54 
     55  int32_t mStart;
     56  int32_t mEnd;
     57  mozilla::SelectionType mSelectionType;
     58  mozilla::dom::HighlightSelectionData mHighlightData;
     59  mozilla::TextRangeStyle mTextRangeStyle;
     60  mozilla::UniquePtr<SelectionDetails> mNext;
     61 };
     62 
     63 struct SelectionCustomColors {
     64 #ifdef NS_BUILD_REFCNT_LOGGING
     65  MOZ_COUNTED_DEFAULT_CTOR(SelectionCustomColors)
     66  MOZ_COUNTED_DTOR(SelectionCustomColors)
     67 #endif
     68  mozilla::Maybe<nscolor> mForegroundColor;
     69  mozilla::Maybe<nscolor> mBackgroundColor;
     70  mozilla::Maybe<nscolor> mAltForegroundColor;
     71  mozilla::Maybe<nscolor> mAltBackgroundColor;
     72 };
     73 
     74 namespace mozilla {
     75 class PresShell;
     76 
     77 /** PeekOffsetStruct is used to group various arguments (both input and output)
     78 *  that are passed to nsIFrame::PeekOffset(). See below for the description of
     79 *  individual arguments.
     80 */
     81 enum class PeekOffsetOption : uint16_t {
     82  // Whether to allow jumping across line boundaries.
     83  //
     84  // Used with: eSelectCharacter, eSelectWord.
     85  JumpLines,
     86 
     87  // Whether we should preserve or trim spaces at begin/end of content
     88  PreserveSpaces,
     89 
     90  // Whether to stop when reaching a scroll view boundary.
     91  //
     92  // Used with: eSelectCharacter, eSelectWord, eSelectLine.
     93  StopAtScroller,
     94 
     95  // Whether to stop when reaching a placeholder frame.
     96  StopAtPlaceholder,
     97 
     98  // Whether the peeking is done in response to a keyboard action.
     99  //
    100  // Used with: eSelectWord.
    101  IsKeyboardSelect,
    102 
    103  // Whether bidi caret behavior is visual (set) or logical (unset).
    104  //
    105  // Used with: eSelectCharacter, eSelectWord, eSelectBeginLine, eSelectEndLine.
    106  Visual,
    107 
    108  // Whether the selection is being extended or moved.
    109  Extend,
    110 
    111  // If true, the offset has to end up in an editable node, otherwise we'll keep
    112  // searching.
    113  ForceEditableRegion,
    114 };
    115 
    116 using PeekOffsetOptions = EnumSet<PeekOffsetOption>;
    117 
    118 struct MOZ_STACK_CLASS PeekOffsetStruct {
    119  PeekOffsetStruct(nsSelectionAmount aAmount, nsDirection aDirection,
    120                   int32_t aStartOffset, nsPoint aDesiredCaretPos,
    121                   // Passing by value here is intentional because EnumSet
    122                   // is optimized as uint*_t in opt builds.
    123                   const PeekOffsetOptions aOptions,
    124                   EWordMovementType aWordMovementType = eDefaultBehavior,
    125                   const dom::Element* aAncestorLimiter = nullptr);
    126 
    127  /**
    128   * Return true if the ancestor limiter is not specified or if the content for
    129   * aFrame is an inclusive descendant of mAncestorLimiter.
    130   */
    131  [[nodiscard]] bool FrameContentIsInAncestorLimiter(
    132      const nsIFrame* aFrame) const {
    133    return !mAncestorLimiter ||
    134           (aFrame->GetContent() &&
    135            aFrame->GetContent()->IsInclusiveDescendantOf(mAncestorLimiter));
    136  }
    137 
    138  // Note: Most arguments (input and output) are only used with certain values
    139  // of mAmount. These values are indicated for each argument below.
    140  // Arguments with no such indication are used with all values of mAmount.
    141 
    142  /*** Input arguments ***/
    143  // Note: The value of some of the input arguments may be changed upon exit.
    144 
    145  // The type of movement requested (by character, word, line, etc.)
    146  nsSelectionAmount mAmount;
    147 
    148  // eDirPrevious or eDirNext.
    149  //
    150  // Note for visual bidi movement:
    151  //   * eDirPrevious means 'left-then-up' if the containing block is LTR,
    152  //     'right-then-up' if it is RTL.
    153  //   * eDirNext means 'right-then-down' if the containing block is LTR,
    154  //     'left-then-down' if it is RTL.
    155  //   * Between paragraphs, eDirPrevious means "go to the visual end of
    156  //     the previous paragraph", and eDirNext means "go to the visual
    157  //     beginning of the next paragraph".
    158  //
    159  // Used with: eSelectCharacter, eSelectWord, eSelectLine, eSelectParagraph.
    160  const nsDirection mDirection;
    161 
    162  // Offset into the content of the current frame where the peek starts.
    163  //
    164  // Used with: eSelectCharacter, eSelectWord
    165  int32_t mStartOffset;
    166 
    167  // The desired inline coordinate for the caret (one of .x or .y will be used,
    168  // depending on line's writing mode)
    169  //
    170  // Used with: eSelectLine.
    171  const nsPoint mDesiredCaretPos;
    172 
    173  // An enum that determines whether to prefer the start or end of a word or to
    174  // use the default behavior, which is a combination of direction and the
    175  // platform-based pref "layout.word_select.eat_space_to_next_word"
    176  EWordMovementType mWordMovementType;
    177 
    178  PeekOffsetOptions mOptions;
    179 
    180  // The ancestor limiter element to peek offset.
    181  const dom::Element* const mAncestorLimiter;
    182 
    183  /*** Output arguments ***/
    184 
    185  // Content reached as a result of the peek.
    186  nsCOMPtr<nsIContent> mResultContent;
    187 
    188  // Frame reached as a result of the peek.
    189  //
    190  // Used with: eSelectCharacter, eSelectWord.
    191  nsIFrame* mResultFrame;
    192 
    193  // Offset into content reached as a result of the peek.
    194  int32_t mContentOffset;
    195 
    196  // When the result position is between two frames, indicates which of the two
    197  // frames the caret should be painted in. false means "the end of the frame
    198  // logically before the caret", true means "the beginning of the frame
    199  // logically after the caret".
    200  //
    201  // Used with: eSelectLine, eSelectBeginLine, eSelectEndLine.
    202  CaretAssociationHint mAttach;
    203 };
    204 
    205 struct LimitersAndCaretData;
    206 
    207 }  // namespace mozilla
    208 
    209 struct nsPrevNextBidiLevels {
    210  void SetData(nsIFrame* aFrameBefore, nsIFrame* aFrameAfter,
    211               mozilla::intl::BidiEmbeddingLevel aLevelBefore,
    212               mozilla::intl::BidiEmbeddingLevel aLevelAfter) {
    213    mFrameBefore = aFrameBefore;
    214    mFrameAfter = aFrameAfter;
    215    mLevelBefore = aLevelBefore;
    216    mLevelAfter = aLevelAfter;
    217  }
    218  nsIFrame* mFrameBefore;
    219  nsIFrame* mFrameAfter;
    220  mozilla::intl::BidiEmbeddingLevel mLevelBefore;
    221  mozilla::intl::BidiEmbeddingLevel mLevelAfter;
    222 };
    223 
    224 namespace mozilla {
    225 class SelectionChangeEventDispatcher;
    226 namespace dom {
    227 class Highlight;
    228 class Selection;
    229 enum class ClickSelectionType { NotApplicable, Double, Triple };
    230 }  // namespace dom
    231 
    232 /**
    233 * Constants for places that want to handle table selections.  These
    234 * indicate what part of a table is being selected.
    235 */
    236 enum class TableSelectionMode : uint32_t {
    237  None,     /* Nothing being selected; not valid in all cases. */
    238  Cell,     /* A cell is being selected. */
    239  Row,      /* A row is being selected. */
    240  Column,   /* A column is being selected. */
    241  Table,    /* A table (including cells and captions) is being selected. */
    242  AllCells, /* All the cells in a table are being selected. */
    243 };
    244 
    245 }  // namespace mozilla
    246 
    247 class nsFrameSelection final {
    248 public:
    249  friend std::ostream& operator<<(std::ostream&, const nsFrameSelection&);
    250 
    251  using CaretAssociationHint = mozilla::CaretAssociationHint;
    252  using Element = mozilla::dom::Element;
    253 
    254  /*interfaces for addref and release and queryinterface*/
    255 
    256  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsFrameSelection)
    257  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsFrameSelection)
    258 
    259  enum class FocusMode {
    260    kExtendSelection,     /** Keep old anchor point. */
    261    kCollapseToNewPoint,  /** Collapses the Selection to the new point. */
    262    kMultiRangeSelection, /** Keeps existing non-collapsed ranges and marks them
    263                             as generated. */
    264  };
    265 
    266  /**
    267   * HandleClick will take the focus to the new frame at the new offset and
    268   * will either extend the selection from the old anchor, or replace the old
    269   * anchor. the old anchor and focus position may also be used to deselect
    270   * things
    271   *
    272   * @param aNewfocus is the content that wants the focus
    273   *
    274   * @param aContentOffset is the content offset of the parent aNewFocus
    275   *
    276   * @param aContentOffsetEnd is the content offset of the parent aNewFocus and
    277   * is specified different when you need to select to and include both start
    278   * and end points
    279   *
    280   * @param aHint will tell the selection which direction geometrically to
    281   * actually show the caret on. 1 = end of this line 0 = beginning of this line
    282   */
    283  MOZ_CAN_RUN_SCRIPT nsresult HandleClick(nsIContent* aNewFocus,
    284                                          uint32_t aContentOffset,
    285                                          uint32_t aContentEndOffset,
    286                                          FocusMode aFocusMode,
    287                                          CaretAssociationHint aHint);
    288 
    289 public:
    290  /**
    291   * Sets the type of the selection based on whether a selection is created
    292   * by doubleclick, long tapping a word or tripleclick.
    293   *
    294   * @param aClickSelectionType   ClickSelectionType::Double if the selection
    295   *                              is created by doubleclick,
    296   *                              ClickSelectionType::Triple if the selection
    297   *                              is created by tripleclick.
    298   */
    299  void SetClickSelectionType(
    300      mozilla::dom::ClickSelectionType aClickSelectionType) {
    301    mClickSelectionType = aClickSelectionType;
    302  }
    303 
    304  /**
    305   * Return true if this is an instance for an independent selection.
    306   * Currently, independent selection is created only in the text controls
    307   * to manage selections in their native anonymous subtree.
    308   */
    309  [[nodiscard]] bool IsIndependentSelection() const {
    310    return !!GetIndependentSelectionRootElement();
    311  }
    312 
    313  /**
    314   * Returns true if the selection was created by doubleclick or
    315   * long tap over a word.
    316   */
    317  [[nodiscard]] bool IsDoubleClickSelection() const {
    318    return mClickSelectionType == mozilla::dom::ClickSelectionType::Double;
    319  }
    320 
    321  /**
    322   * Returns true if the selection was created by triple click
    323   */
    324  [[nodiscard]] bool IsTripleClickSelection() const {
    325    return mClickSelectionType == mozilla::dom::ClickSelectionType::Triple;
    326  }
    327 
    328  /**
    329   * HandleDrag extends the selection to contain the frame closest to aPoint.
    330   *
    331   * @param aPresContext is the context to use when figuring out what frame
    332   * contains the point.
    333   *
    334   * @param aFrame is the parent of all frames to use when searching for the
    335   * closest frame to the point.
    336   *
    337   * @param aPoint is relative to aFrame
    338   */
    339  MOZ_CAN_RUN_SCRIPT void HandleDrag(nsIFrame* aFrame, const nsPoint& aPoint);
    340 
    341  /**
    342   * HandleTableSelection will set selection to a table, cell, etc
    343   * depending on information contained in aFlags
    344   *
    345   * @param aParentContent is the paretent of either a table or cell that user
    346   * clicked or dragged the mouse in
    347   *
    348   * @param aContentOffset is the offset of the table or cell
    349   *
    350   * @param aTarget indicates what to select
    351   *   * TableSelectionMode::Cell
    352   *       We should select a cell (content points to the cell)
    353   *   * TableSelectionMode::Row
    354   *       We should select a row (content points to any cell in row)
    355   *   * TableSelectionMode::Column
    356   *       We should select a row (content points to any cell in column)
    357   *   * TableSelectionMode::Table
    358   *       We should select a table (content points to the table)
    359   *   * TableSelectionMode::AllCells
    360   *       We should select all cells (content points to any cell in table)
    361   *
    362   * @param aMouseEvent passed in so we can get where event occurred
    363   * and what keys are pressed
    364   */
    365  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
    366  HandleTableSelection(nsINode* aParentContent, int32_t aContentOffset,
    367                       mozilla::TableSelectionMode aTarget,
    368                       mozilla::WidgetMouseEvent* aMouseEvent);
    369 
    370  /**
    371   * Add cell to the selection with `SelectionType::eNormal`.
    372   *
    373   * @param  aCell  [in] HTML td element.
    374   */
    375  nsresult SelectCellElement(nsIContent* aCell);
    376 
    377 public:
    378  /**
    379   * Remove cells from selection inside of the given cell range.
    380   *
    381   * @param  aTable             [in] HTML table element
    382   * @param  aStartRowIndex     [in] row index where the cells range starts
    383   * @param  aStartColumnIndex  [in] column index where the cells range starts
    384   * @param  aEndRowIndex       [in] row index where the cells range ends
    385   * @param  aEndColumnIndex    [in] column index where the cells range ends
    386   */
    387  MOZ_CAN_RUN_SCRIPT nsresult RemoveCellsFromSelection(
    388      nsIContent* aTable, int32_t aStartRowIndex, int32_t aStartColumnIndex,
    389      int32_t aEndRowIndex, int32_t aEndColumnIndex);
    390 
    391  /**
    392   * Remove cells from selection outside of the given cell range.
    393   *
    394   * @param  aTable             [in] HTML table element
    395   * @param  aStartRowIndex     [in] row index where the cells range starts
    396   * @param  aStartColumnIndex  [in] column index where the cells range starts
    397   * @param  aEndRowIndex       [in] row index where the cells range ends
    398   * @param  aEndColumnIndex    [in] column index where the cells range ends
    399   */
    400  MOZ_CAN_RUN_SCRIPT nsresult RestrictCellsToSelection(
    401      nsIContent* aTable, int32_t aStartRowIndex, int32_t aStartColumnIndex,
    402      int32_t aEndRowIndex, int32_t aEndColumnIndex);
    403 
    404  /**
    405   * StartAutoScrollTimer is responsible for scrolling frames so that
    406   * aPoint is always visible, and for selecting any frame that contains
    407   * aPoint. The timer will also reset itself to fire again if we have
    408   * not scrolled to the end of the document.
    409   *
    410   * @param aFrame is the outermost frame to use when searching for
    411   * the closest frame for the point, i.e. the frame that is capturing
    412   * the mouse
    413   *
    414   * @param aPoint is relative to aFrame.
    415   *
    416   * @param aDelay is the timer's interval.
    417   */
    418  MOZ_CAN_RUN_SCRIPT nsresult StartAutoScrollTimer(nsIFrame* aFrame,
    419                                                   const nsPoint& aPoint,
    420                                                   uint32_t aDelay);
    421 
    422  /**
    423   * Stops any active auto scroll timer.
    424   */
    425  void StopAutoScrollTimer();
    426 
    427  /**
    428   * Returns in frame coordinates the selection beginning and ending with the
    429   * type of selection given
    430   *
    431   * @param aContent is the content asking
    432   * @param aContentOffset is the starting content boundary
    433   * @param aContentLength is the length of the content piece asking
    434   * @param aIgnoreSelection is Yes, this won't return selection details about
    435   * the normal selection.
    436   */
    437  enum class IgnoreNormalSelection : bool { No, Yes };
    438  mozilla::UniquePtr<SelectionDetails> LookUpSelection(
    439      nsIContent* aContent, int32_t aContentOffset, int32_t aContentLength,
    440      IgnoreNormalSelection aIgnoreNormalSelection) const;
    441 
    442  /**
    443   * Sets the drag state to aState for resons of drag state.
    444   *
    445   * @param aState is the new state of drag
    446   */
    447  MOZ_CAN_RUN_SCRIPT void SetDragState(bool aState);
    448 
    449  /**
    450   * Gets the drag state to aState for resons of drag state.
    451   *
    452   * @param aState will hold the state of drag
    453   */
    454  [[nodiscard]] bool GetDragState() const { return mDragState; }
    455 
    456  /**
    457   * If we are in table cell selection mode. aka ctrl click in table cell
    458   */
    459  [[nodiscard]] bool IsInTableSelectionMode() const {
    460    return mTableSelection.mMode != mozilla::TableSelectionMode::None;
    461  }
    462  void ClearTableCellSelection() {
    463    mTableSelection.mMode = mozilla::TableSelectionMode::None;
    464  }
    465 
    466  /**
    467   * No query interface for selection. must use this method now.
    468   *
    469   * @param aSelectionType The selection type what you want.
    470   */
    471  [[nodiscard]] mozilla::dom::Selection* GetSelection(
    472      mozilla::SelectionType aSelectionType) const;
    473 
    474  /**
    475   * Convenience method to access the `eNormal` Selection.
    476   */
    477  [[nodiscard]] mozilla::dom::Selection& NormalSelection() const {
    478    return *GetSelection(mozilla::SelectionType::eNormal);
    479  }
    480 
    481  /**
    482   * Returns the number of highlight selections.
    483   */
    484  [[nodiscard]] size_t HighlightSelectionCount() const {
    485    return mHighlightSelections.Length();
    486  }
    487 
    488  /**
    489   * Get a highlight selection by index. The index must be valid.
    490   */
    491  [[nodiscard]] RefPtr<mozilla::dom::Selection> HighlightSelection(
    492      size_t aIndex) const {
    493    return mHighlightSelections[aIndex].second();
    494  }
    495 
    496  /**
    497   * @brief Adds a highlight selection for `aHighlight`.
    498   */
    499  MOZ_CAN_RUN_SCRIPT void AddHighlightSelection(
    500      nsAtom* aHighlightName, mozilla::dom::Highlight& aHighlight);
    501 
    502  void RepaintHighlightSelection(nsAtom* aHighlightName);
    503 
    504  /**
    505   * @brief Removes the Highlight selection identified by `aHighlightName`.
    506   */
    507  MOZ_CAN_RUN_SCRIPT void RemoveHighlightSelection(nsAtom* aHighlightName);
    508 
    509  /**
    510   * @brief Adds a new range to the highlight selection.
    511   *
    512   * If there is no highlight selection for the given highlight yet, it is
    513   * created using |AddHighlightSelection|.
    514   */
    515  MOZ_CAN_RUN_SCRIPT void AddHighlightSelectionRange(
    516      nsAtom* aHighlightName, mozilla::dom::Highlight& aHighlight,
    517      mozilla::dom::AbstractRange& aRange);
    518 
    519  /**
    520   * @brief Removes a range from a highlight selection.
    521   */
    522  MOZ_CAN_RUN_SCRIPT void RemoveHighlightSelectionRange(
    523      nsAtom* aHighlightName, mozilla::dom::AbstractRange& aRange);
    524  /**
    525   * ScrollSelectionIntoView scrolls a region of the selection,
    526   * so that it is visible in the scrolled view.
    527   *
    528   * @param aSelectionType the selection to scroll into view.
    529   *
    530   * @param aRegion the region inside the selection to scroll into view.
    531   *
    532   * @param aFlags the scroll flags.  Valid bits include:
    533   *   * SCROLL_SYNCHRONOUS: when set, scrolls the selection into view
    534   *     before returning. If not set, posts a request which is processed
    535   *     at some point after the method returns.
    536   *   * SCROLL_FIRST_ANCESTOR_ONLY: if set, only the first ancestor will be
    537   *     scrolled into view.
    538   */
    539  MOZ_CAN_RUN_SCRIPT nsresult
    540  ScrollSelectionIntoView(mozilla::SelectionType aSelectionType,
    541                          SelectionRegion aRegion, int16_t aFlags) const;
    542 
    543  /**
    544   * RepaintSelection repaints the selected frames that are inside the
    545   * selection specified by aSelectionType.
    546   *
    547   * @param aSelectionType The selection type what you want to repaint.
    548   */
    549  nsresult RepaintSelection(mozilla::SelectionType aSelectionType);
    550 
    551  /**
    552   * Return true if aContainerNode is in the selection limiter or the ancestor
    553   * limiter if one of them is set.
    554   *
    555   * Note that this returns true when aContainerNode may be in the scope of
    556   * an independent selection.  Therefore, even if this returns `true`,
    557   * aContainerNode may not be valid container node for a selection managed
    558   * by this instance.
    559   */
    560  [[nodiscard]] bool NodeIsInLimiters(const nsINode* aContainerNode) const;
    561 
    562  [[nodiscard]] static bool NodeIsInLimiters(
    563      const nsINode* aContainerNode,
    564      const Element* aIndependentSelectionLimiterElement,
    565      const Element* aSelectionAncestorLimiter);
    566 
    567  /**
    568   * GetFrameToPageSelect() returns a frame which is ancestor limit of
    569   * per-page selection.  The frame may not be scrollable.  E.g.,
    570   * when selection ancestor limit is set to a frame of an editing host of
    571   * contenteditable element and it's not scrollable.
    572   */
    573  [[nodiscard]] nsIFrame* GetFrameToPageSelect() const;
    574 
    575  /**
    576   * This method moves caret (if aExtend is false) or expands selection (if
    577   * aExtend is true).  Then, scrolls aFrame one page.  Finally, this may
    578   * call ScrollSelectionIntoView() for making focus of selection visible
    579   * but depending on aSelectionIntoView value.
    580   *
    581   * @param aForward if true, scroll forward if not scroll backward
    582   * @param aExtend  if true, extend selection to the new point
    583   * @param aFrame   the frame to scroll or container of per-page selection.
    584   *                 if aExtend is true and selection may have ancestor limit,
    585   *                 should set result of GetFrameToPageSelect().
    586   * @param aSelectionIntoView
    587   *                 If IfChanged, this makes selection into view only when
    588   *                 selection is modified by the call.
    589   *                 If Yes, this makes selection into view always.
    590   */
    591  enum class SelectionIntoView { IfChanged, Yes };
    592  MOZ_CAN_RUN_SCRIPT nsresult PageMove(bool aForward, bool aExtend,
    593                                       nsIFrame* aFrame,
    594                                       SelectionIntoView aSelectionIntoView);
    595 
    596  void SetHint(CaretAssociationHint aHintRight) { mCaret.mHint = aHintRight; }
    597  [[nodiscard]] CaretAssociationHint GetHint() const { return mCaret.mHint; }
    598 
    599  void SetCaretBidiLevelAndMaybeSchedulePaint(
    600      mozilla::intl::BidiEmbeddingLevel aLevel);
    601 
    602  /**
    603   * GetCaretBidiLevel gets the caret bidi level.
    604   */
    605  [[nodiscard]] mozilla::intl::BidiEmbeddingLevel GetCaretBidiLevel() const;
    606 
    607  /**
    608   * UndefineCaretBidiLevel sets the caret bidi level to "undefined".
    609   */
    610  void UndefineCaretBidiLevel();
    611 
    612  /**
    613   * PhysicalMove will generally be called from the nsiselectioncontroller
    614   * implementations. the effect being the selection will move one unit
    615   * 'aAmount' in the given aDirection.
    616   * @param aDirection  the direction to move the selection
    617   * @param aAmount     amount of movement (char/line; word/page; eol/doc)
    618   * @param aExtend     continue selection
    619   */
    620  MOZ_CAN_RUN_SCRIPT nsresult PhysicalMove(int16_t aDirection, int16_t aAmount,
    621                                           bool aExtend);
    622 
    623  /**
    624   * CharacterMove will generally be called from the nsiselectioncontroller
    625   * implementations. the effect being the selection will move one character
    626   * left or right.
    627   * @param aForward move forward in document.
    628   * @param aExtend continue selection
    629   */
    630  MOZ_CAN_RUN_SCRIPT nsresult CharacterMove(bool aForward, bool aExtend);
    631 
    632  /**
    633   * WordMove will generally be called from the nsiselectioncontroller
    634   * implementations. the effect being the selection will move one word left or
    635   * right.
    636   * @param aForward move forward in document.
    637   * @param aExtend continue selection
    638   */
    639  MOZ_CAN_RUN_SCRIPT nsresult WordMove(bool aForward, bool aExtend);
    640 
    641  /**
    642   * LineMove will generally be called from the nsiselectioncontroller
    643   * implementations. the effect being the selection will move one line up or
    644   * down.
    645   * @param aForward move forward in document.
    646   * @param aExtend continue selection
    647   */
    648  MOZ_CAN_RUN_SCRIPT nsresult LineMove(bool aForward, bool aExtend);
    649 
    650  /**
    651   * IntraLineMove will generally be called from the nsiselectioncontroller
    652   * implementations. the effect being the selection will move to beginning or
    653   * end of line
    654   * @param aForward move forward in document.
    655   * @param aExtend continue selection
    656   */
    657  MOZ_CAN_RUN_SCRIPT nsresult IntraLineMove(bool aForward, bool aExtend);
    658 
    659  /**
    660   * CreateRangeExtendedToNextGraphemeClusterBoundary() returns range which is
    661   * extended from normal selection range to start of next grapheme cluster
    662   * boundary.
    663   *
    664   * @param aLimitersAndCaretData       The data of limiters and additional
    665   *                                    caret data.
    666   * @param aRange                      The range which you want to extend.
    667   * @param aRangeDirection             eDirNext if the start boundary of
    668   *                                    aRange is focus.  Otherwise, i.e., if
    669   *                                    the start boundary is anchor,
    670   *                                    eDirPrevious.
    671   */
    672  template <typename RangeType>
    673  MOZ_CAN_RUN_SCRIPT static mozilla::Result<RefPtr<RangeType>, nsresult>
    674  CreateRangeExtendedToNextGraphemeClusterBoundary(
    675      mozilla::PresShell& aPresShell,
    676      const mozilla::LimitersAndCaretData& aLimitersAndCaretData,
    677      const mozilla::dom::AbstractRange& aRange, nsDirection aRangeDirection) {
    678    return CreateRangeExtendedToSomewhere<RangeType>(
    679        aPresShell, aLimitersAndCaretData, aRange, aRangeDirection, eDirNext,
    680        eSelectCluster, eLogical);
    681  }
    682 
    683  /**
    684   * CreateRangeExtendedToPreviousCharacterBoundary() returns range which is
    685   * extended from normal selection range to start of previous character
    686   * boundary.
    687   *
    688   * @param aLimitersAndCaretData       The data of limiters and additional
    689   *                                    caret data.
    690   * @param aRange                      The range which you want to extend.
    691   * @param aRangeDirection             eDirNext if the start boundary of
    692   *                                    aRange is focus.  Otherwise, i.e., if
    693   *                                    the start boundary is anchor,
    694   *                                    eDirPrevious.
    695   */
    696  template <typename RangeType>
    697  MOZ_CAN_RUN_SCRIPT static mozilla::Result<RefPtr<RangeType>, nsresult>
    698  CreateRangeExtendedToPreviousCharacterBoundary(
    699      mozilla::PresShell& aPresShell,
    700      const mozilla::LimitersAndCaretData& aLimitersAndCaretData,
    701      const mozilla::dom::AbstractRange& aRange, nsDirection aRangeDirection) {
    702    return CreateRangeExtendedToSomewhere<RangeType>(
    703        aPresShell, aLimitersAndCaretData, aRange, aRangeDirection,
    704        eDirPrevious, eSelectCharacter, eLogical);
    705  }
    706 
    707  /**
    708   * CreateRangeExtendedToNextWordBoundary() returns range which is
    709   * extended from normal selection range to start of next word boundary.
    710   *
    711   * @param aLimitersAndCaretData       The data of limiters and additional
    712   *                                    caret data.
    713   * @param aRange                      The range which you want to extend.
    714   * @param aRangeDirection             eDirNext if the start boundary of
    715   *                                    aRange is focus.  Otherwise, i.e., if
    716   *                                    the start boundary is anchor,
    717   *                                    eDirPrevious.
    718   */
    719  template <typename RangeType>
    720  MOZ_CAN_RUN_SCRIPT static mozilla::Result<RefPtr<RangeType>, nsresult>
    721  CreateRangeExtendedToNextWordBoundary(
    722      mozilla::PresShell& aPresShell,
    723      const mozilla::LimitersAndCaretData& aLimitersAndCaretData,
    724      const mozilla::dom::AbstractRange& aRange, nsDirection aRangeDirection) {
    725    return CreateRangeExtendedToSomewhere<RangeType>(
    726        aPresShell, aLimitersAndCaretData, aRange, aRangeDirection, eDirNext,
    727        eSelectWord, eLogical);
    728  }
    729 
    730  /**
    731   * CreateRangeExtendedToPreviousWordBoundary() returns range which is
    732   * extended from normal selection range to start of previous word boundary.
    733   *
    734   * @param aLimitersAndCaretData       The data of limiters and additional
    735   *                                    caret data.
    736   * @param aRange                      The range which you want to extend.
    737   * @param aRangeDirection             eDirNext if the start boundary of
    738   *                                    aRange is focus.  Otherwise, i.e., if
    739   *                                    the start boundary is anchor,
    740   *                                    eDirPrevious.
    741   */
    742  template <typename RangeType>
    743  MOZ_CAN_RUN_SCRIPT static mozilla::Result<RefPtr<RangeType>, nsresult>
    744  CreateRangeExtendedToPreviousWordBoundary(
    745      mozilla::PresShell& aPresShell,
    746      const mozilla::LimitersAndCaretData& aLimitersAndCaretData,
    747      const mozilla::dom::AbstractRange& aRange, nsDirection aRangeDirection) {
    748    return CreateRangeExtendedToSomewhere<RangeType>(
    749        aPresShell, aLimitersAndCaretData, aRange, aRangeDirection,
    750        eDirPrevious, eSelectWord, eLogical);
    751  }
    752 
    753  /**
    754   * CreateRangeExtendedToPreviousHardLineBreak() returns range which is
    755   * extended from normal selection range to previous hard line break.
    756   *
    757   * @param aLimitersAndCaretData       The data of limiters and additional
    758   *                                    caret data.
    759   * @param aRange                      The range which you want to extend.
    760   * @param aRangeDirection             eDirNext if the start boundary of
    761   *                                    aRange is focus.  Otherwise, i.e., if
    762   *                                    the start boundary is anchor,
    763   *                                    eDirPrevious.
    764   */
    765  template <typename RangeType>
    766  MOZ_CAN_RUN_SCRIPT static mozilla::Result<RefPtr<RangeType>, nsresult>
    767  CreateRangeExtendedToPreviousHardLineBreak(
    768      mozilla::PresShell& aPresShell,
    769      const mozilla::LimitersAndCaretData& aLimitersAndCaretData,
    770      const mozilla::dom::AbstractRange& aRange, nsDirection aRangeDirection) {
    771    return CreateRangeExtendedToSomewhere<RangeType>(
    772        aPresShell, aLimitersAndCaretData, aRange, aRangeDirection,
    773        eDirPrevious, eSelectBeginLine, eLogical);
    774  }
    775 
    776  /**
    777   * CreateRangeExtendedToNextHardLineBreak() returns range which is extended
    778   * from normal selection range to next hard line break.
    779   *
    780   * @param aLimitersAndCaretData       The data of limiters and additional
    781   *                                    caret data.
    782   * @param aRange                      The range which you want to extend.
    783   * @param aRangeDirection             eDirNext if the start boundary of
    784   *                                    aRange is focus.  Otherwise, i.e., if
    785   *                                    the start boundary is anchor,
    786   *                                    eDirPrevious.
    787   */
    788  template <typename RangeType>
    789  MOZ_CAN_RUN_SCRIPT static mozilla::Result<RefPtr<RangeType>, nsresult>
    790  CreateRangeExtendedToNextHardLineBreak(
    791      mozilla::PresShell& aPresShell,
    792      const mozilla::LimitersAndCaretData& aLimitersAndCaretData,
    793      const mozilla::dom::AbstractRange& aRange, nsDirection aRangeDirection) {
    794    return CreateRangeExtendedToSomewhere<RangeType>(
    795        aPresShell, aLimitersAndCaretData, aRange, aRangeDirection, eDirNext,
    796        eSelectEndLine, eLogical);
    797  }
    798 
    799  /** Sets/Gets The display selection enum.
    800   */
    801  void SetDisplaySelection(int16_t aState) { mDisplaySelection = aState; }
    802  [[nodiscard]] int16_t GetDisplaySelection() const {
    803    return mDisplaySelection;
    804  }
    805 
    806  /**
    807   * This method can be used to store the data received during a MouseDown
    808   * event so that we can place the caret during the MouseUp event.
    809   *
    810   * @param aMouseEvent the event received by the selection MouseDown
    811   * handling method. A nullptr value can be use to tell this method
    812   * that any data is storing is no longer valid.
    813   */
    814  void SetDelayedCaretData(mozilla::WidgetMouseEvent* aMouseEvent);
    815 
    816  /**
    817   * Get the delayed MouseDown event data necessary to place the
    818   * caret during MouseUp processing.
    819   *
    820   * @return a pointer to the event received
    821   * by the selection during MouseDown processing. It can be nullptr
    822   * if the data is no longer valid.
    823   */
    824  [[nodiscard]] bool HasDelayedCaretData() const {
    825    return mDelayedMouseEvent.mIsValid;
    826  }
    827  [[nodiscard]] bool IsShiftDownInDelayedCaretData() const {
    828    NS_ASSERTION(mDelayedMouseEvent.mIsValid, "No valid delayed caret data");
    829    return mDelayedMouseEvent.mIsShift;
    830  }
    831  [[nodiscard]] uint32_t GetClickCountInDelayedCaretData() const {
    832    NS_ASSERTION(mDelayedMouseEvent.mIsValid, "No valid delayed caret data");
    833    return mDelayedMouseEvent.mClickCount;
    834  }
    835 
    836  [[nodiscard]] bool MouseDownRecorded() const {
    837    return !GetDragState() && HasDelayedCaretData() &&
    838           GetClickCountInDelayedCaretData() < 2;
    839  }
    840 
    841  /**
    842   * Returns the selection root element if and only if the instance is for an
    843   * independent selection.  Currently, this is a native anonymous `<div>` for
    844   * a text control.
    845   */
    846  [[nodiscard]] Element* GetIndependentSelectionRootElement() const {
    847    return mLimiters.mIndependentSelectionRootElement;
    848  }
    849 
    850  /**
    851   * Get the independent selection root parent which is usually a text control
    852   * element which hosts the anonymous subtree managed by this frame selection.
    853   */
    854  [[nodiscard]] Element* GetIndependentSelectionRootParentElement() const {
    855    MOZ_DIAGNOSTIC_ASSERT(IsIndependentSelection());
    856    return Element::FromNodeOrNull(
    857        mLimiters.mIndependentSelectionRootElement
    858            ->GetClosestNativeAnonymousSubtreeRootParentOrHost());
    859  }
    860 
    861  /**
    862   * GetAncestorLimiter() returns the root of current selection ranges.  This is
    863   * typically the focused editing host unless it's the root element of the
    864   * document.
    865   */
    866  [[nodiscard]] Element* GetAncestorLimiter() const {
    867    return mLimiters.mAncestorLimiter;
    868  }
    869 
    870  [[nodiscard]] Element* GetAncestorLimiterOrIndependentSelectionRootElement()
    871      const {
    872    return mLimiters.mAncestorLimiter
    873               ? mLimiters.mAncestorLimiter
    874               : mLimiters.mIndependentSelectionRootElement;
    875  }
    876 
    877  /**
    878   * Set ancestor limiter.  If aLimiter is not nullptr, this adjusts all
    879   * selection ranges into the limiter element.  Thus, calling this may run
    880   * the selection listeners.
    881   */
    882  MOZ_CAN_RUN_SCRIPT void SetAncestorLimiter(Element* aLimiter);
    883 
    884  /**
    885   * GetPrevNextBidiLevels will return the frames and associated Bidi levels of
    886   * the characters logically before and after a (collapsed) selection.
    887   *
    888   * @param aNode is the node containing the selection
    889   * @param aContentOffset is the offset of the selection in the node
    890   * @param aJumpLines
    891   *   If true, look across line boundaries.
    892   *   If false, behave as if there were base-level frames at line edges.
    893   *
    894   * @return A struct holding the before/after frame and the before/after
    895   * level.
    896   *
    897   * At the beginning and end of each line there is assumed to be a frame with
    898   * Bidi level equal to the paragraph embedding level.
    899   *
    900   * In these cases the before frame and after frame respectively will be
    901   * nullptr.
    902   */
    903  [[nodiscard]] nsPrevNextBidiLevels GetPrevNextBidiLevels(
    904      nsIContent* aNode, uint32_t aContentOffset, bool aJumpLines) const;
    905 
    906  /**
    907   * MaintainSelection will track the normal selection as being "sticky".
    908   * Dragging or extending selection will never allow for a subset
    909   * (or the whole) of the maintained selection to become unselected.
    910   * Primary use: double click selecting then dragging on second click
    911   *
    912   * @param aAmount the initial amount of text selected (word, line or
    913   * paragraph). For "line", use eSelectBeginLine.
    914   */
    915  nsresult MaintainSelection(nsSelectionAmount aAmount = eSelectNoAmount);
    916 
    917  MOZ_CAN_RUN_SCRIPT nsresult ConstrainFrameAndPointToAnchorSubtree(
    918      nsIFrame* aFrame, const nsPoint& aPoint, nsIFrame** aRetFrame,
    919      nsPoint& aRetPoint) const;
    920 
    921  /**
    922   * @param aPresShell is the parameter to be used for most of the other calls
    923   * for callbacks etc
    924   *
    925   * @param aAccessibleCaretEnabled true if we should enable the accessible
    926   * caret.
    927   *
    928   * @param aEditorRootAnonymousDiv if this instance is for an independent
    929   * selection for a text control, specify this to the anonymous <div> element
    930   * of the text control which contains only an editable Text and/or a <br>.
    931   */
    932  nsFrameSelection(mozilla::PresShell* aPresShell, bool aAccessibleCaretEnabled,
    933                   Element* aEditorRootAnonymousDiv = nullptr);
    934 
    935  /**
    936   * @param aRequesterFuncName function name which wants to start the batch.
    937   * This won't be stored nor exposed to selection listeners etc, used only for
    938   * logging.
    939   */
    940  void StartBatchChanges(const char* aRequesterFuncName);
    941 
    942  /**
    943   * @param aRequesterFuncName function name which wants to end the batch.
    944   * This won't be stored nor exposed to selection listeners etc, used only for
    945   * logging.
    946   * @param aReasons potentially multiple of the reasons defined in
    947   * nsISelectionListener.idl
    948   */
    949  MOZ_CAN_RUN_SCRIPT void EndBatchChanges(
    950      const char* aRequesterFuncName,
    951      int16_t aReasons = nsISelectionListener::NO_REASON);
    952 
    953  [[nodiscard]] mozilla::PresShell* GetPresShell() const { return mPresShell; }
    954 
    955  void DisconnectFromPresShell();
    956  MOZ_CAN_RUN_SCRIPT nsresult ClearNormalSelection();
    957 
    958  // Table selection support.
    959  static nsITableCellLayout* GetCellLayout(const nsIContent* aCellContent);
    960 
    961 private:
    962  ~nsFrameSelection();
    963 
    964  // TODO: in case an error is returned, it sometimes refers to a programming
    965  // error, in other cases to runtime errors. This deserves to be cleaned up.
    966  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
    967  TakeFocus(nsIContent& aNewFocus, uint32_t aContentOffset,
    968            uint32_t aContentEndOffset, CaretAssociationHint aHint,
    969            FocusMode aFocusMode);
    970 
    971  /**
    972   * After moving the caret, its Bidi level is set according to the following
    973   * rules:
    974   *
    975   * After moving over a character with left/right arrow, set to the Bidi level
    976   * of the last moved over character. After Home and End, set to the paragraph
    977   * embedding level. After up/down arrow, PageUp/Down, set to the lower level
    978   * of the 2 surrounding characters. After mouse click, set to the level of the
    979   * current frame.
    980   *
    981   * The following two methods use GetPrevNextBidiLevels to determine the new
    982   * Bidi level. BidiLevelFromMove is called when the caret is moved in response
    983   * to a keyboard event
    984   *
    985   * @param aPresShell is the presentation shell
    986   * @param aNode is the content node
    987   * @param aContentOffset is the new caret position, as an offset into aNode
    988   * @param aAmount is the amount of the move that gave the caret its new
    989   * position
    990   * @param aHint is the hint indicating in what logical direction the caret
    991   * moved
    992   */
    993  void BidiLevelFromMove(mozilla::PresShell* aPresShell, nsIContent* aNode,
    994                         uint32_t aContentOffset, nsSelectionAmount aAmount,
    995                         CaretAssociationHint aHint);
    996  /**
    997   * BidiLevelFromClick is called when the caret is repositioned by clicking the
    998   * mouse
    999   *
   1000   * @param aNode is the content node
   1001   * @param aContentOffset is the new caret position, as an offset into aNode
   1002   */
   1003  void BidiLevelFromClick(nsIContent* aNewFocus, uint32_t aContentOffset);
   1004 
   1005  /**
   1006   * @param aReasons potentially multiple of the reasons defined in
   1007   * nsISelectionListener.idl.
   1008   */
   1009  void SetChangeReasons(int16_t aReasons) {
   1010    mSelectionChangeReasons = aReasons;
   1011  }
   1012 
   1013  /**
   1014   * @param aReasons potentially multiple of the reasons defined in
   1015   * nsISelectionListener.idl.
   1016   */
   1017  void AddChangeReasons(int16_t aReasons) {
   1018    mSelectionChangeReasons |= aReasons;
   1019  }
   1020 
   1021  /**
   1022   * @return potentially multiple of the reasons defined in
   1023   * nsISelectionListener.idl.
   1024   */
   1025  [[nodiscard]] int16_t PopChangeReasons() {
   1026    int16_t retval = mSelectionChangeReasons;
   1027    mSelectionChangeReasons = nsISelectionListener::NO_REASON;
   1028    return retval;
   1029  }
   1030 
   1031  [[nodiscard]] nsSelectionAmount GetCaretMoveAmount() {
   1032    return mCaretMoveAmount;
   1033  }
   1034 
   1035  [[nodiscard]] bool IsUserSelectionReason() const {
   1036    return (mSelectionChangeReasons &
   1037            (nsISelectionListener::DRAG_REASON |
   1038             nsISelectionListener::MOUSEDOWN_REASON |
   1039             nsISelectionListener::MOUSEUP_REASON |
   1040             nsISelectionListener::KEYPRESS_REASON)) !=
   1041           nsISelectionListener::NO_REASON;
   1042  }
   1043 
   1044  friend class mozilla::dom::Selection;
   1045  friend class mozilla::SelectionChangeEventDispatcher;
   1046  friend struct mozilla::AutoPrepareFocusRange;
   1047 
   1048  /*HELPER METHODS*/
   1049  // Whether MoveCaret should use logical or visual movement,
   1050  // or follow the bidi.edit.caret_movement_style preference.
   1051  enum CaretMovementStyle { eLogical, eVisual, eUsePrefStyle };
   1052  enum class ExtendSelection : bool { No, Yes };
   1053  MOZ_CAN_RUN_SCRIPT nsresult MoveCaret(nsDirection aDirection,
   1054                                        ExtendSelection aExtendSelection,
   1055                                        nsSelectionAmount aAmount,
   1056                                        CaretMovementStyle aMovementStyle);
   1057 
   1058  /**
   1059   * @brief Creates `PeekOffsetOptions` for caret move operations.
   1060   *
   1061   * @param aSelection       The selection object. Must be non-null
   1062   * @param aExtendSelection Whether the selection should be extended or not
   1063   * @param aMovementStyle   The `CaretMovementStyle` (logical or visual)
   1064   * @return mozilla::Result<mozilla::PeekOffsetOptions, nsresult>
   1065   */
   1066  [[nodiscard]] mozilla::Result<mozilla::PeekOffsetOptions, nsresult>
   1067  CreatePeekOffsetOptionsForCaretMove(mozilla::dom::Selection* aSelection,
   1068                                      ExtendSelection aExtendSelection,
   1069                                      CaretMovementStyle aMovementStyle) const {
   1070    MOZ_ASSERT(aSelection);
   1071    return CreatePeekOffsetOptionsForCaretMove(
   1072        mLimiters.mIndependentSelectionRootElement,
   1073        static_cast<ForceEditableRegion>(aSelection->IsEditorSelection()),
   1074        aExtendSelection, aMovementStyle);
   1075  }
   1076 
   1077  enum class ForceEditableRegion : bool { No, Yes };
   1078  [[nodiscard]] static mozilla::Result<mozilla::PeekOffsetOptions, nsresult>
   1079  CreatePeekOffsetOptionsForCaretMove(const Element* aSelectionLimiter,
   1080                                      ForceEditableRegion aForceEditableRegion,
   1081                                      ExtendSelection aExtendSelection,
   1082                                      CaretMovementStyle aMovementStyle);
   1083 
   1084  /**
   1085   * @brief Get the Ancestor Limiter for caret move operation.
   1086   *
   1087   * If the selection is an editor selection, the correct editing host is
   1088   * identified and chosen as limiting element.
   1089   *
   1090   * @param aSelection The selection object. Must be non-null
   1091   * @return The ancestor limiter, or nullptr.
   1092   */
   1093  [[nodiscard]] mozilla::Result<Element*, nsresult>
   1094  GetAncestorLimiterForCaretMove(mozilla::dom::Selection* aSelection) const;
   1095 
   1096  /**
   1097   * CreateRangeExtendedToSomewhere() is common method to implement
   1098   * CreateRangeExtendedTo*().  This method creates a range extended from
   1099   * aRange.
   1100   *
   1101   * @param aLimitersAndCaretData       The data of limiters and additional
   1102   *                                    caret data.
   1103   * @param aRange                      The range which you want to extend.
   1104   * @param aRangeDirection             eDirNext if the start boundary of
   1105   *                                    aRange is focus.  Otherwise, i.e., if
   1106   *                                    the start boundary is anchor,
   1107   *                                    eDirPrevious.
   1108   * @param aExtendDirection            Whether you want to extend the range
   1109   *                                    backward or forward.
   1110   * @param aAmount                     The amount which you want to extend.
   1111   * @param aMovementStyle              Whether visual or logical.
   1112   */
   1113  template <typename RangeType>
   1114  MOZ_CAN_RUN_SCRIPT static mozilla::Result<RefPtr<RangeType>, nsresult>
   1115  CreateRangeExtendedToSomewhere(
   1116      mozilla::PresShell& aPresShell,
   1117      const mozilla::LimitersAndCaretData& aLimitersAndCaretData,
   1118      const mozilla::dom::AbstractRange& aRange, nsDirection aRangeDirection,
   1119      nsDirection aExtendDirection, const nsSelectionAmount aAmount,
   1120      CaretMovementStyle aMovementStyle);
   1121 
   1122  void InvalidateDesiredCaretPos();  // do not listen to mDesiredCaretPos.mValue
   1123                                     // you must get another.
   1124 
   1125  [[nodiscard]] bool IsBatching() const { return mBatching.mCounter > 0; }
   1126 
   1127  enum class IsBatchingEnd : bool { No, Yes };
   1128 
   1129  // nsFrameSelection may get deleted when calling this,
   1130  // so remember to use nsCOMPtr when needed.
   1131  MOZ_CAN_RUN_SCRIPT nsresult
   1132  NotifySelectionListeners(mozilla::SelectionType aSelectionType,
   1133                           IsBatchingEnd aEndBatching = IsBatchingEnd::No);
   1134 
   1135  static nsresult GetCellIndexes(const nsIContent* aCell, int32_t& aRowIndex,
   1136                                 int32_t& aColIndex);
   1137 
   1138  [[nodiscard]] static nsIContent* GetFirstCellNodeInRange(
   1139      const nsRange* aRange);
   1140  // Returns non-null table if in same table, null otherwise
   1141  [[nodiscard]] static nsIContent* IsInSameTable(const nsIContent* aContent1,
   1142                                                 const nsIContent* aContent2);
   1143  // Might return null
   1144  [[nodiscard]] static nsIContent* GetParentTable(const nsIContent* aCellNode);
   1145 
   1146  ////////////BEGIN nsFrameSelection members
   1147 
   1148  RefPtr<mozilla::dom::Selection>
   1149      mDomSelections[sizeof(mozilla::kPresentSelectionTypes) /
   1150                     sizeof(mozilla::SelectionType)];
   1151 
   1152  nsTArray<
   1153      mozilla::CompactPair<RefPtr<nsAtom>, RefPtr<mozilla::dom::Selection>>>
   1154      mHighlightSelections;
   1155 
   1156  struct TableSelection {
   1157    // Get our first range, if its first selected node is a cell.  If this does
   1158    // not return null, then the first node in the returned range is a cell
   1159    // (according to GetFirstCellNodeInRange).
   1160    nsRange* GetFirstCellRange(const mozilla::dom::Selection& aNormalSelection);
   1161 
   1162    // Get our next range, if its first selected node is a cell.  If this does
   1163    // not return null, then the first node in the returned range is a cell
   1164    // (according to GetFirstCellNodeInRange).
   1165    nsRange* GetNextCellRange(const mozilla::dom::Selection& aNormalSelection);
   1166 
   1167    [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
   1168    HandleSelection(nsINode* aParentContent, int32_t aContentOffset,
   1169                    mozilla::TableSelectionMode aTarget,
   1170                    mozilla::WidgetMouseEvent* aMouseEvent, bool aDragState,
   1171                    mozilla::dom::Selection& aNormalSelection);
   1172 
   1173    /**
   1174     * @return the closest inclusive table cell ancestor
   1175     *         (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of
   1176     *         aContent, if it is actively editable.
   1177     */
   1178    [[nodiscard]] static nsINode* IsContentInActivelyEditableTableCell(
   1179        nsPresContext* aContext, nsIContent* aContent);
   1180 
   1181    // TODO: annotate this with `MOZ_CAN_RUN_SCRIPT` instead.
   1182    MOZ_CAN_RUN_SCRIPT nsresult
   1183    SelectBlockOfCells(nsIContent* aStartCell, nsIContent* aEndCell,
   1184                       mozilla::dom::Selection& aNormalSelection);
   1185 
   1186    MOZ_CAN_RUN_SCRIPT nsresult SelectRowOrColumn(
   1187        nsIContent* aCellContent, mozilla::dom::Selection& aNormalSelection);
   1188 
   1189    MOZ_CAN_RUN_SCRIPT nsresult
   1190    UnselectCells(const nsIContent* aTable, int32_t aStartRowIndex,
   1191                  int32_t aStartColumnIndex, int32_t aEndRowIndex,
   1192                  int32_t aEndColumnIndex, bool aRemoveOutsideOfCellRange,
   1193                  mozilla::dom::Selection& aNormalSelection);
   1194 
   1195    nsCOMPtr<nsINode>
   1196        mClosestInclusiveTableCellAncestor;  // used to snap to table selection
   1197    nsCOMPtr<nsIContent> mStartSelectedCell;
   1198    nsCOMPtr<nsIContent> mEndSelectedCell;
   1199    nsCOMPtr<nsIContent> mAppendStartSelectedCell;
   1200    nsCOMPtr<nsIContent> mUnselectCellOnMouseUp;
   1201    mozilla::TableSelectionMode mMode = mozilla::TableSelectionMode::None;
   1202    int32_t mSelectedCellIndex = 0;
   1203    bool mDragSelectingCells = false;
   1204 
   1205   private:
   1206    struct MOZ_STACK_CLASS FirstAndLastCell {
   1207      nsCOMPtr<nsIContent> mFirst;
   1208      nsCOMPtr<nsIContent> mLast;
   1209    };
   1210 
   1211    [[nodiscard]] mozilla::Result<FirstAndLastCell, nsresult>
   1212    FindFirstAndLastCellOfRowOrColumn(const nsIContent& aCellContent) const;
   1213 
   1214    [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandleDragSelecting(
   1215        mozilla::TableSelectionMode aTarget, nsIContent* aChildContent,
   1216        const mozilla::WidgetMouseEvent* aMouseEvent,
   1217        mozilla::dom::Selection& aNormalSelection);
   1218 
   1219    [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandleMouseUpOrDown(
   1220        mozilla::TableSelectionMode aTarget, bool aDragState,
   1221        nsIContent* aChildContent, nsINode* aParentContent,
   1222        int32_t aContentOffset, const mozilla::WidgetMouseEvent* aMouseEvent,
   1223        mozilla::dom::Selection& aNormalSelection);
   1224 
   1225    class MOZ_STACK_CLASS RowAndColumnRelation;
   1226  };
   1227 
   1228  TableSelection mTableSelection;
   1229 
   1230  struct MaintainedRange {
   1231    /**
   1232     * Ensure anchor and focus of aNormalSelection are ordered appropriately
   1233     * relative to the maintained range.
   1234     */
   1235    MOZ_CAN_RUN_SCRIPT void AdjustNormalSelection(
   1236        const nsIContent* aContent, int32_t aOffset,
   1237        mozilla::dom::Selection& aNormalSelection) const;
   1238 
   1239    /**
   1240     * @param aStopAtScroller   If yes, this will
   1241     *                          set `PeekOffsetOption::StopAtScroller`.
   1242     */
   1243    enum class StopAtScroller : bool { No, Yes };
   1244    void AdjustContentOffsets(nsIFrame::ContentOffsets& aOffsets,
   1245                              StopAtScroller aStopAtScroller) const;
   1246 
   1247    void MaintainAnchorFocusRange(
   1248        const mozilla::dom::Selection& aNormalSelection,
   1249        nsSelectionAmount aAmount);
   1250 
   1251    RefPtr<nsRange> mRange;
   1252    nsSelectionAmount mAmount = eSelectNoAmount;
   1253  };
   1254 
   1255  MaintainedRange mMaintainedRange;
   1256 
   1257  struct Batching {
   1258    uint32_t mCounter = 0;
   1259  };
   1260 
   1261  Batching mBatching;
   1262 
   1263  struct Limiters {
   1264    // The independent selection root element if and only if the
   1265    // nsFrameSelection instance is for an independent selection.
   1266    RefPtr<Element> mIndependentSelectionRootElement;
   1267    // Limit selection navigation to a descendant of this element.
   1268    // This is typically the focused editing host if set unless it's the root
   1269    // element of the document.
   1270    RefPtr<Element> mAncestorLimiter;
   1271  };
   1272 
   1273  Limiters mLimiters;
   1274 
   1275  mozilla::PresShell* mPresShell = nullptr;
   1276  // Reasons for notifications of selection changing.
   1277  // Can be multiple of the reasons defined in nsISelectionListener.idl.
   1278  int16_t mSelectionChangeReasons = nsISelectionListener::NO_REASON;
   1279  // For visual display purposes.
   1280  int16_t mDisplaySelection = nsISelectionController::SELECTION_OFF;
   1281  nsSelectionAmount mCaretMoveAmount = eSelectNoAmount;
   1282 
   1283  struct Caret {
   1284    // Hint to tell if the selection is at the end of this line or beginning of
   1285    // next.
   1286    CaretAssociationHint mHint = CaretAssociationHint::Before;
   1287    mozilla::intl::BidiEmbeddingLevel mBidiLevel = BIDI_LEVEL_UNDEFINED;
   1288 
   1289    [[nodiscard]] static bool IsVisualMovement(
   1290        ExtendSelection aExtendSelection, CaretMovementStyle aMovementStyle);
   1291  };
   1292 
   1293  Caret mCaret;
   1294 
   1295  mozilla::intl::BidiEmbeddingLevel mKbdBidiLevel =
   1296      mozilla::intl::BidiEmbeddingLevel::LTR();
   1297 
   1298  class DesiredCaretPos {
   1299   public:
   1300    // the position requested by the Key Handling for up down
   1301    nsresult FetchPos(nsPoint& aDesiredCaretPos,
   1302                      const mozilla::PresShell& aPresShell,
   1303                      mozilla::dom::Selection& aNormalSelection) const;
   1304 
   1305    void Set(const nsPoint& aPos);
   1306 
   1307    void Invalidate();
   1308 
   1309    bool mIsSet = false;
   1310 
   1311   private:
   1312    nsPoint mValue;
   1313  };
   1314 
   1315  DesiredCaretPos mDesiredCaretPos;
   1316 
   1317  struct DelayedMouseEvent {
   1318    bool mIsValid = false;
   1319    // These values are not used since they are only valid when mIsValid is
   1320    // true, and setting mIsValid  always overrides these values.
   1321    bool mIsShift = false;
   1322    uint32_t mClickCount = 0;
   1323  };
   1324 
   1325  DelayedMouseEvent mDelayedMouseEvent;
   1326 
   1327  bool mDragState = false;  // for drag purposes
   1328  bool mAccessibleCaretEnabled = false;
   1329 
   1330  // Records if a selection was created by doubleclicking or tripleclicking
   1331  // a word. This information is needed later on to determine if a leading
   1332  // or trailing whitespace needs to be removed as well to achieve
   1333  // native behaviour on macOS.
   1334  mozilla::dom::ClickSelectionType mClickSelectionType =
   1335      mozilla::dom::ClickSelectionType::NotApplicable;
   1336 };
   1337 
   1338 /**
   1339 * Selection Batcher class that supports multiple FrameSelections.
   1340 */
   1341 class MOZ_RAII AutoFrameSelectionBatcher final {
   1342 public:
   1343  MOZ_CAN_RUN_SCRIPT explicit AutoFrameSelectionBatcher(
   1344      const char* aFunctionName, size_t aEstimatedSize = 1)
   1345      : mFunctionName(aFunctionName) {
   1346    mFrameSelections.SetCapacity(aEstimatedSize);
   1347  }
   1348  MOZ_CAN_RUN_SCRIPT ~AutoFrameSelectionBatcher() {
   1349    for (const auto& frameSelection : mFrameSelections) {
   1350      MOZ_KnownLive(frameSelection)->EndBatchChanges(mFunctionName);
   1351    }
   1352  }
   1353  void AddFrameSelection(nsFrameSelection* aFrameSelection) {
   1354    if (!aFrameSelection) {
   1355      return;
   1356    }
   1357    aFrameSelection->StartBatchChanges(mFunctionName);
   1358    mFrameSelections.AppendElement(aFrameSelection);
   1359  }
   1360 
   1361 private:
   1362  const char* mFunctionName;
   1363  AutoTArray<RefPtr<nsFrameSelection>, 1> mFrameSelections;
   1364 };
   1365 
   1366 namespace mozilla {
   1367 /**
   1368 * A struct for sharing nsFrameSelection outside of its instance.
   1369 */
   1370 struct LimitersAndCaretData {
   1371  using Element = dom::Element;
   1372 
   1373  LimitersAndCaretData() = default;
   1374  explicit LimitersAndCaretData(const nsFrameSelection& aFrameSelection)
   1375      : mIndependentSelectionRootElement(
   1376            aFrameSelection.GetIndependentSelectionRootElement()),
   1377        mAncestorLimiter(aFrameSelection.GetAncestorLimiter()),
   1378        mCaretAssociationHint(aFrameSelection.GetHint()),
   1379        mCaretBidiLevel(aFrameSelection.GetCaretBidiLevel()) {}
   1380 
   1381  [[nodiscard]] bool NodeIsInLimiters(const nsINode* aContainerNode) const {
   1382    return nsFrameSelection::NodeIsInLimiters(
   1383        aContainerNode, mIndependentSelectionRootElement, mAncestorLimiter);
   1384  }
   1385  [[nodiscard]] bool RangeInLimiters(const dom::AbstractRange& aRange) const {
   1386    return NodeIsInLimiters(aRange.GetStartContainer()) &&
   1387           (!aRange.IsPositionedAndSameContainer() ||
   1388            NodeIsInLimiters(aRange.GetEndContainer()));
   1389  }
   1390 
   1391  // nsFrameSelection::GetIndependentSelectionRootElement
   1392  RefPtr<Element> mIndependentSelectionRootElement;
   1393  // nsFrameSelection::GetAncestorLimiter
   1394  RefPtr<Element> mAncestorLimiter;
   1395  // nsFrameSelection::GetHint
   1396  CaretAssociationHint mCaretAssociationHint = CaretAssociationHint::Before;
   1397  // nsFrameSelection::GetCaretBidiLevel
   1398  intl::BidiEmbeddingLevel mCaretBidiLevel;
   1399 };
   1400 
   1401 }  // namespace mozilla
   1402 
   1403 #endif /* nsFrameSelection_h___ */