Bug 1688832: part 9) Change argument of `nsFrameSelection::TakeFocus` from pointer...
[gecko.git] / layout / generic / nsFrameSelection.h
blobd11659c2b6e2eff8a243177c2cac49bb32edd478
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/. */
7 #ifndef nsFrameSelection_h___
8 #define nsFrameSelection_h___
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/EventForwards.h"
13 #include "mozilla/dom/Selection.h"
14 #include "mozilla/Result.h"
15 #include "mozilla/TextRange.h"
16 #include "mozilla/UniquePtr.h"
17 #include "nsIFrame.h"
18 #include "nsIContent.h"
19 #include "nsISelectionController.h"
20 #include "nsISelectionListener.h"
21 #include "nsITableCellLayout.h"
22 #include "WordMovementType.h"
23 #include "CaretAssociationHint.h"
24 #include "nsBidiPresUtils.h"
26 class nsRange;
28 #define BIDI_LEVEL_UNDEFINED 0x80
30 //----------------------------------------------------------------------
32 // Selection interface
34 struct SelectionDetails {
35 SelectionDetails()
36 : mStart(), mEnd(), mSelectionType(mozilla::SelectionType::eInvalid) {
37 MOZ_COUNT_CTOR(SelectionDetails);
39 MOZ_COUNTED_DTOR(SelectionDetails)
41 int32_t mStart;
42 int32_t mEnd;
43 mozilla::SelectionType mSelectionType;
44 mozilla::TextRangeStyle mTextRangeStyle;
45 mozilla::UniquePtr<SelectionDetails> mNext;
48 struct SelectionCustomColors {
49 #ifdef NS_BUILD_REFCNT_LOGGING
50 MOZ_COUNTED_DEFAULT_CTOR(SelectionCustomColors)
51 MOZ_COUNTED_DTOR(SelectionCustomColors)
52 #endif
53 mozilla::Maybe<nscolor> mForegroundColor;
54 mozilla::Maybe<nscolor> mBackgroundColor;
55 mozilla::Maybe<nscolor> mAltForegroundColor;
56 mozilla::Maybe<nscolor> mAltBackgroundColor;
59 namespace mozilla {
60 class PresShell;
61 } // namespace mozilla
63 /** PeekOffsetStruct is used to group various arguments (both input and output)
64 * that are passed to nsIFrame::PeekOffset(). See below for the description of
65 * individual arguments.
67 struct MOZ_STACK_CLASS nsPeekOffsetStruct {
68 enum class ForceEditableRegion {
69 No,
70 Yes,
73 nsPeekOffsetStruct(
74 nsSelectionAmount aAmount, nsDirection aDirection, int32_t aStartOffset,
75 nsPoint aDesiredCaretPos, bool aJumpLines, bool aScrollViewStop,
76 bool aIsKeyboardSelect, bool aVisual, bool aExtend,
77 ForceEditableRegion = ForceEditableRegion::No,
78 mozilla::EWordMovementType aWordMovementType = mozilla::eDefaultBehavior,
79 bool aTrimSpaces = true);
81 // Note: Most arguments (input and output) are only used with certain values
82 // of mAmount. These values are indicated for each argument below.
83 // Arguments with no such indication are used with all values of mAmount.
85 /*** Input arguments ***/
86 // Note: The value of some of the input arguments may be changed upon exit.
88 // The type of movement requested (by character, word, line, etc.)
89 nsSelectionAmount mAmount;
91 // eDirPrevious or eDirNext.
93 // Note for visual bidi movement:
94 // * eDirPrevious means 'left-then-up' if the containing block is LTR,
95 // 'right-then-up' if it is RTL.
96 // * eDirNext means 'right-then-down' if the containing block is LTR,
97 // 'left-then-down' if it is RTL.
98 // * Between paragraphs, eDirPrevious means "go to the visual end of
99 // the previous paragraph", and eDirNext means "go to the visual
100 // beginning of the next paragraph".
102 // Used with: eSelectCharacter, eSelectWord, eSelectLine, eSelectParagraph.
103 const nsDirection mDirection;
105 // Offset into the content of the current frame where the peek starts.
107 // Used with: eSelectCharacter, eSelectWord
108 int32_t mStartOffset;
110 // The desired inline coordinate for the caret (one of .x or .y will be used,
111 // depending on line's writing mode)
113 // Used with: eSelectLine.
114 const nsPoint mDesiredCaretPos;
116 // An enum that determines whether to prefer the start or end of a word or to
117 // use the default beahvior, which is a combination of direction and the
118 // platform-based pref "layout.word_select.eat_space_to_next_word"
119 mozilla::EWordMovementType mWordMovementType;
121 // Whether to allow jumping across line boundaries.
123 // Used with: eSelectCharacter, eSelectWord.
124 const bool mJumpLines;
126 // mTrimSpaces: Whether we should trim spaces at begin/end of content
127 const bool mTrimSpaces;
129 // Whether to stop when reaching a scroll view boundary.
131 // Used with: eSelectCharacter, eSelectWord, eSelectLine.
132 const bool mScrollViewStop;
134 // Whether the peeking is done in response to a keyboard action.
136 // Used with: eSelectWord.
137 const bool mIsKeyboardSelect;
139 // Whether bidi caret behavior is visual (true) or logical (false).
141 // Used with: eSelectCharacter, eSelectWord, eSelectBeginLine, eSelectEndLine.
142 const bool mVisual;
144 // Whether the selection is being extended or moved.
145 const bool mExtend;
147 // If true, the offset has to end up in an editable node, otherwise we'll keep
148 // searching.
149 const bool mForceEditableRegion;
151 /*** Output arguments ***/
153 // Content reached as a result of the peek.
154 nsCOMPtr<nsIContent> mResultContent;
156 // Frame reached as a result of the peek.
158 // Used with: eSelectCharacter, eSelectWord.
159 nsIFrame* mResultFrame;
161 // Offset into content reached as a result of the peek.
162 int32_t mContentOffset;
164 // When the result position is between two frames, indicates which of the two
165 // frames the caret should be painted in. false means "the end of the frame
166 // logically before the caret", true means "the beginning of the frame
167 // logically after the caret".
169 // Used with: eSelectLine, eSelectBeginLine, eSelectEndLine.
170 mozilla::CaretAssociationHint mAttach;
173 struct nsPrevNextBidiLevels {
174 void SetData(nsIFrame* aFrameBefore, nsIFrame* aFrameAfter,
175 nsBidiLevel aLevelBefore, nsBidiLevel aLevelAfter) {
176 mFrameBefore = aFrameBefore;
177 mFrameAfter = aFrameAfter;
178 mLevelBefore = aLevelBefore;
179 mLevelAfter = aLevelAfter;
181 nsIFrame* mFrameBefore;
182 nsIFrame* mFrameAfter;
183 nsBidiLevel mLevelBefore;
184 nsBidiLevel mLevelAfter;
187 namespace mozilla {
188 class SelectionChangeEventDispatcher;
189 namespace dom {
190 class Selection;
191 } // namespace dom
194 * Constants for places that want to handle table selections. These
195 * indicate what part of a table is being selected.
197 enum class TableSelectionMode : uint32_t {
198 None, /* Nothing being selected; not valid in all cases. */
199 Cell, /* A cell is being selected. */
200 Row, /* A row is being selected. */
201 Column, /* A column is being selected. */
202 Table, /* A table (including cells and captions) is being selected. */
203 AllCells, /* All the cells in a table are being selected. */
206 } // namespace mozilla
207 class nsIScrollableFrame;
209 class nsFrameSelection final {
210 public:
211 typedef mozilla::CaretAssociationHint CaretAssociateHint;
213 /*interfaces for addref and release and queryinterface*/
215 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsFrameSelection)
216 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsFrameSelection)
218 enum class FocusMode {
219 kExtendSelection, /** Keep old anchor point. */
220 kCollapseToNewPoint, /** Collapses the Selection to the new point. */
221 kMultiRangeSelection, /** Keeps existing non-collapsed ranges and marks them
222 as generated. */
226 * HandleClick will take the focus to the new frame at the new offset and
227 * will either extend the selection from the old anchor, or replace the old
228 * anchor. the old anchor and focus position may also be used to deselect
229 * things
231 * @param aNewfocus is the content that wants the focus
233 * @param aContentOffset is the content offset of the parent aNewFocus
235 * @param aContentOffsetEnd is the content offset of the parent aNewFocus and
236 * is specified different when you need to select to and include both start
237 * and end points
239 * @param aHint will tell the selection which direction geometrically to
240 * actually show the caret on. 1 = end of this line 0 = beginning of this line
242 MOZ_CAN_RUN_SCRIPT nsresult HandleClick(nsIContent* aNewFocus,
243 uint32_t aContentOffset,
244 uint32_t aContentEndOffset,
245 FocusMode aFocusMode,
246 CaretAssociateHint aHint);
249 * HandleDrag extends the selection to contain the frame closest to aPoint.
251 * @param aPresContext is the context to use when figuring out what frame
252 * contains the point.
254 * @param aFrame is the parent of all frames to use when searching for the
255 * closest frame to the point.
257 * @param aPoint is relative to aFrame
259 MOZ_CAN_RUN_SCRIPT void HandleDrag(nsIFrame* aFrame, const nsPoint& aPoint);
262 * HandleTableSelection will set selection to a table, cell, etc
263 * depending on information contained in aFlags
265 * @param aParentContent is the paretent of either a table or cell that user
266 * clicked or dragged the mouse in
268 * @param aContentOffset is the offset of the table or cell
270 * @param aTarget indicates what to select
271 * * TableSelectionMode::Cell
272 * We should select a cell (content points to the cell)
273 * * TableSelectionMode::Row
274 * We should select a row (content points to any cell in row)
275 * * TableSelectionMode::Column
276 * We should select a row (content points to any cell in column)
277 * * TableSelectionMode::Table
278 * We should select a table (content points to the table)
279 * * TableSelectionMode::AllCells
280 * We should select all cells (content points to any cell in table)
282 * @param aMouseEvent passed in so we can get where event occurred
283 * and what keys are pressed
285 // TODO: replace with `MOZ_CAN_RUN_SCRIPT`.
286 [[nodiscard]] MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
287 HandleTableSelection(nsINode* aParentContent, int32_t aContentOffset,
288 mozilla::TableSelectionMode aTarget,
289 mozilla::WidgetMouseEvent* aMouseEvent);
292 * Add cell to the selection with `SelectionType::eNormal`.
294 * @param aCell [in] HTML td element.
296 nsresult SelectCellElement(nsIContent* aCell);
298 public:
300 * Remove cells from selection inside of the given cell range.
302 * @param aTable [in] HTML table element
303 * @param aStartRowIndex [in] row index where the cells range starts
304 * @param aStartColumnIndex [in] column index where the cells range starts
305 * @param aEndRowIndex [in] row index where the cells range ends
306 * @param aEndColumnIndex [in] column index where the cells range ends
308 // TODO: annotate this with `MOZ_CAN_RUN_SCRIPT` instead.
309 MOZ_CAN_RUN_SCRIPT_BOUNDARY
310 nsresult RemoveCellsFromSelection(nsIContent* aTable, int32_t aStartRowIndex,
311 int32_t aStartColumnIndex,
312 int32_t aEndRowIndex,
313 int32_t aEndColumnIndex);
316 * Remove cells from selection outside of the given cell range.
318 * @param aTable [in] HTML table element
319 * @param aStartRowIndex [in] row index where the cells range starts
320 * @param aStartColumnIndex [in] column index where the cells range starts
321 * @param aEndRowIndex [in] row index where the cells range ends
322 * @param aEndColumnIndex [in] column index where the cells range ends
324 // TODO: annotate this with `MOZ_CAN_RUN_SCRIPT` instead.
325 MOZ_CAN_RUN_SCRIPT_BOUNDARY
326 nsresult RestrictCellsToSelection(nsIContent* aTable, int32_t aStartRowIndex,
327 int32_t aStartColumnIndex,
328 int32_t aEndRowIndex,
329 int32_t aEndColumnIndex);
332 * StartAutoScrollTimer is responsible for scrolling frames so that
333 * aPoint is always visible, and for selecting any frame that contains
334 * aPoint. The timer will also reset itself to fire again if we have
335 * not scrolled to the end of the document.
337 * @param aFrame is the outermost frame to use when searching for
338 * the closest frame for the point, i.e. the frame that is capturing
339 * the mouse
341 * @param aPoint is relative to aFrame.
343 * @param aDelay is the timer's interval.
345 MOZ_CAN_RUN_SCRIPT
346 nsresult StartAutoScrollTimer(nsIFrame* aFrame, const nsPoint& aPoint,
347 uint32_t aDelay);
350 * Stops any active auto scroll timer.
352 void StopAutoScrollTimer();
355 * Returns in frame coordinates the selection beginning and ending with the
356 * type of selection given
358 * @param aContent is the content asking
359 * @param aContentOffset is the starting content boundary
360 * @param aContentLength is the length of the content piece asking
361 * @param aSlowCheck will check using slow method with no shortcuts
363 mozilla::UniquePtr<SelectionDetails> LookUpSelection(nsIContent* aContent,
364 int32_t aContentOffset,
365 int32_t aContentLength,
366 bool aSlowCheck) const;
369 * Sets the drag state to aState for resons of drag state.
371 * @param aState is the new state of drag
373 MOZ_CAN_RUN_SCRIPT
374 void SetDragState(bool aState);
377 * Gets the drag state to aState for resons of drag state.
379 * @param aState will hold the state of drag
381 bool GetDragState() const { return mDragState; }
384 * If we are in table cell selection mode. aka ctrl click in table cell
386 bool IsInTableSelectionMode() const {
387 return mTableSelection.mMode != mozilla::TableSelectionMode::None;
389 void ClearTableCellSelection() {
390 mTableSelection.mMode = mozilla::TableSelectionMode::None;
394 * No query interface for selection. must use this method now.
396 * @param aSelectionType The selection type what you want.
398 mozilla::dom::Selection* GetSelection(
399 mozilla::SelectionType aSelectionType) const;
402 * ScrollSelectionIntoView scrolls a region of the selection,
403 * so that it is visible in the scrolled view.
405 * @param aSelectionType the selection to scroll into view.
407 * @param aRegion the region inside the selection to scroll into view.
409 * @param aFlags the scroll flags. Valid bits include:
410 * * SCROLL_SYNCHRONOUS: when set, scrolls the selection into view
411 * before returning. If not set, posts a request which is processed
412 * at some point after the method returns.
413 * * SCROLL_FIRST_ANCESTOR_ONLY: if set, only the first ancestor will be
414 * scrolled into view.
416 // TODO: replace with `MOZ_CAN_RUN_SCRIPT`.
417 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
418 ScrollSelectionIntoView(mozilla::SelectionType aSelectionType,
419 SelectionRegion aRegion, int16_t aFlags) const;
422 * RepaintSelection repaints the selected frames that are inside the
423 * selection specified by aSelectionType.
425 * @param aSelectionType The selection type what you want to repaint.
427 nsresult RepaintSelection(mozilla::SelectionType aSelectionType);
429 bool IsValidSelectionPoint(nsINode* aNode) const;
432 * Given a node and its child offset, return the nsIFrame and the offset into
433 * that frame.
435 * @param aNode input parameter for the node to look at
436 * @param aOffset offset into above node.
437 * @param aReturnOffset will contain offset into frame.
439 static nsIFrame* GetFrameForNodeOffset(nsIContent* aNode, int32_t aOffset,
440 CaretAssociateHint aHint,
441 int32_t* aReturnOffset);
444 * GetFrameToPageSelect() returns a frame which is ancestor limit of
445 * per-page selection. The frame may not be scrollable. E.g.,
446 * when selection ancestor limit is set to a frame of an editing host of
447 * contenteditable element and it's not scrollable.
449 nsIFrame* GetFrameToPageSelect() const;
452 * This method moves caret (if aExtend is false) or expands selection (if
453 * aExtend is true). Then, scrolls aFrame one page. Finally, this may
454 * call ScrollSelectionIntoView() for making focus of selection visible
455 * but depending on aSelectionIntoView value.
457 * @param aForward if true, scroll forward if not scroll backward
458 * @param aExtend if true, extend selection to the new point
459 * @param aFrame the frame to scroll or container of per-page selection.
460 * if aExtend is true and selection may have ancestor limit,
461 * should set result of GetFrameToPageSelect().
462 * @param aSelectionIntoView
463 * If IfChanged, this makes selection into view only when
464 * selection is modified by the call.
465 * If Yes, this makes selection into view always.
467 enum class SelectionIntoView { IfChanged, Yes };
468 MOZ_CAN_RUN_SCRIPT nsresult PageMove(bool aForward, bool aExtend,
469 nsIFrame* aFrame,
470 SelectionIntoView aSelectionIntoView);
472 void SetHint(CaretAssociateHint aHintRight) { mCaret.mHint = aHintRight; }
473 CaretAssociateHint GetHint() const { return mCaret.mHint; }
475 void SetCaretBidiLevelAndMaybeSchedulePaint(nsBidiLevel aLevel);
478 * GetCaretBidiLevel gets the caret bidi level.
480 nsBidiLevel GetCaretBidiLevel() const;
483 * UndefineCaretBidiLevel sets the caret bidi level to "undefined".
485 void UndefineCaretBidiLevel();
488 * PhysicalMove will generally be called from the nsiselectioncontroller
489 * implementations. the effect being the selection will move one unit
490 * 'aAmount' in the given aDirection.
491 * @param aDirection the direction to move the selection
492 * @param aAmount amount of movement (char/line; word/page; eol/doc)
493 * @param aExtend continue selection
495 // TODO: replace with `MOZ_CAN_RUN_SCRIPT`.
496 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult PhysicalMove(int16_t aDirection,
497 int16_t aAmount,
498 bool aExtend);
501 * CharacterMove will generally be called from the nsiselectioncontroller
502 * implementations. the effect being the selection will move one character
503 * left or right.
504 * @param aForward move forward in document.
505 * @param aExtend continue selection
507 // TODO: replace with `MOZ_CAN_RUN_SCRIPT`.
508 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult CharacterMove(bool aForward,
509 bool aExtend);
512 * WordMove will generally be called from the nsiselectioncontroller
513 * implementations. the effect being the selection will move one word left or
514 * right.
515 * @param aForward move forward in document.
516 * @param aExtend continue selection
518 // TODO: replace with `MOZ_CAN_RUN_SCRIPT`.
519 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult WordMove(bool aForward, bool aExtend);
522 * LineMove will generally be called from the nsiselectioncontroller
523 * implementations. the effect being the selection will move one line up or
524 * down.
525 * @param aForward move forward in document.
526 * @param aExtend continue selection
528 // TODO: replace with `MOZ_CAN_RUN_SCRIPT`.
529 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult LineMove(bool aForward, bool aExtend);
532 * IntraLineMove will generally be called from the nsiselectioncontroller
533 * implementations. the effect being the selection will move to beginning or
534 * end of line
535 * @param aForward move forward in document.
536 * @param aExtend continue selection
538 // TODO: replace with `MOZ_CAN_RUN_SCRIPT`.
539 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult IntraLineMove(bool aForward,
540 bool aExtend);
543 * CreateRangeExtendedToNextGraphemeClusterBoundary() returns range which is
544 * extended from normal selection range to start of next grapheme cluster
545 * boundary.
547 template <typename RangeType>
548 MOZ_CAN_RUN_SCRIPT mozilla::Result<RefPtr<RangeType>, nsresult>
549 CreateRangeExtendedToNextGraphemeClusterBoundary() {
550 return CreateRangeExtendedToSomewhere<RangeType>(eDirNext, eSelectCluster,
551 eLogical);
555 * CreateRangeExtendedToPreviousCharacterBoundary() returns range which is
556 * extended from normal selection range to start of previous character
557 * boundary.
559 template <typename RangeType>
560 MOZ_CAN_RUN_SCRIPT mozilla::Result<RefPtr<RangeType>, nsresult>
561 CreateRangeExtendedToPreviousCharacterBoundary() {
562 return CreateRangeExtendedToSomewhere<RangeType>(
563 eDirPrevious, eSelectCharacter, eLogical);
567 * CreateRangeExtendedToNextWordBoundary() returns range which is
568 * extended from normal selection range to start of next word boundary.
570 template <typename RangeType>
571 MOZ_CAN_RUN_SCRIPT mozilla::Result<RefPtr<RangeType>, nsresult>
572 CreateRangeExtendedToNextWordBoundary() {
573 return CreateRangeExtendedToSomewhere<RangeType>(eDirNext, eSelectWord,
574 eLogical);
578 * CreateRangeExtendedToPreviousWordBoundary() returns range which is
579 * extended from normal selection range to start of previous word boundary.
581 template <typename RangeType>
582 MOZ_CAN_RUN_SCRIPT mozilla::Result<RefPtr<RangeType>, nsresult>
583 CreateRangeExtendedToPreviousWordBoundary() {
584 return CreateRangeExtendedToSomewhere<RangeType>(eDirPrevious, eSelectWord,
585 eLogical);
589 * CreateRangeExtendedToPreviousHardLineBreak() returns range which is
590 * extended from normal selection range to previous hard line break.
592 template <typename RangeType>
593 MOZ_CAN_RUN_SCRIPT mozilla::Result<RefPtr<RangeType>, nsresult>
594 CreateRangeExtendedToPreviousHardLineBreak() {
595 return CreateRangeExtendedToSomewhere<RangeType>(
596 eDirPrevious, eSelectBeginLine, eLogical);
600 * CreateRangeExtendedToNextHardLineBreak() returns range which is extended
601 * from normal selection range to next hard line break.
603 template <typename RangeType>
604 MOZ_CAN_RUN_SCRIPT mozilla::Result<RefPtr<RangeType>, nsresult>
605 CreateRangeExtendedToNextHardLineBreak() {
606 return CreateRangeExtendedToSomewhere<RangeType>(eDirNext, eSelectEndLine,
607 eLogical);
610 /** Sets/Gets The display selection enum.
612 void SetDisplaySelection(int16_t aState) { mDisplaySelection = aState; }
613 int16_t GetDisplaySelection() const { return mDisplaySelection; }
616 * This method can be used to store the data received during a MouseDown
617 * event so that we can place the caret during the MouseUp event.
619 * @param aMouseEvent the event received by the selection MouseDown
620 * handling method. A nullptr value can be use to tell this method
621 * that any data is storing is no longer valid.
623 void SetDelayedCaretData(mozilla::WidgetMouseEvent* aMouseEvent);
626 * Get the delayed MouseDown event data necessary to place the
627 * caret during MouseUp processing.
629 * @return a pointer to the event received
630 * by the selection during MouseDown processing. It can be nullptr
631 * if the data is no longer valid.
633 bool HasDelayedCaretData() const { return mDelayedMouseEvent.mIsValid; }
634 bool IsShiftDownInDelayedCaretData() const {
635 NS_ASSERTION(mDelayedMouseEvent.mIsValid, "No valid delayed caret data");
636 return mDelayedMouseEvent.mIsShift;
638 uint32_t GetClickCountInDelayedCaretData() const {
639 NS_ASSERTION(mDelayedMouseEvent.mIsValid, "No valid delayed caret data");
640 return mDelayedMouseEvent.mClickCount;
643 bool MouseDownRecorded() const {
644 return !GetDragState() && HasDelayedCaretData() &&
645 GetClickCountInDelayedCaretData() < 2;
649 * Get the content node that limits the selection
651 * When searching up a nodes for parents, as in a text edit field
652 * in an browser page, we must stop at this node else we reach into the
653 * parent page, which is very bad!
655 nsIContent* GetLimiter() const { return mLimiters.mLimiter; }
657 nsIContent* GetAncestorLimiter() const { return mLimiters.mAncestorLimiter; }
658 MOZ_CAN_RUN_SCRIPT_BOUNDARY void SetAncestorLimiter(nsIContent* aLimiter);
661 * GetPrevNextBidiLevels will return the frames and associated Bidi levels of
662 * the characters logically before and after a (collapsed) selection.
664 * @param aNode is the node containing the selection
665 * @param aContentOffset is the offset of the selection in the node
666 * @param aJumpLines
667 * If true, look across line boundaries.
668 * If false, behave as if there were base-level frames at line edges.
670 * @return A struct holding the before/after frame and the before/after
671 * level.
673 * At the beginning and end of each line there is assumed to be a frame with
674 * Bidi level equal to the paragraph embedding level.
676 * In these cases the before frame and after frame respectively will be
677 * nullptr.
679 nsPrevNextBidiLevels GetPrevNextBidiLevels(nsIContent* aNode,
680 uint32_t aContentOffset,
681 bool aJumpLines) const;
684 * GetFrameFromLevel will scan in a given direction
685 * until it finds a frame with a Bidi level less than or equal to a given
686 * level. It will return the last frame before this.
688 * @param aPresContext is the context to use
689 * @param aFrameIn is the frame to start from
690 * @param aDirection is the direction to scan
691 * @param aBidiLevel is the level to search for
692 * @param aFrameOut will hold the frame returned
694 nsresult GetFrameFromLevel(nsIFrame* aFrameIn, nsDirection aDirection,
695 nsBidiLevel aBidiLevel,
696 nsIFrame** aFrameOut) const;
699 * MaintainSelection will track the normal selection as being "sticky".
700 * Dragging or extending selection will never allow for a subset
701 * (or the whole) of the maintained selection to become unselected.
702 * Primary use: double click selecting then dragging on second click
704 * @param aAmount the initial amount of text selected (word, line or
705 * paragraph). For "line", use eSelectBeginLine.
707 nsresult MaintainSelection(nsSelectionAmount aAmount = eSelectNoAmount);
709 MOZ_CAN_RUN_SCRIPT nsresult ConstrainFrameAndPointToAnchorSubtree(
710 nsIFrame* aFrame, const nsPoint& aPoint, nsIFrame** aRetFrame,
711 nsPoint& aRetPoint) const;
714 * @param aPresShell is the parameter to be used for most of the other calls
715 * for callbacks etc
717 * @param aLimiter limits the selection to nodes with aLimiter parents
719 * @param aAccessibleCaretEnabled true if we should enable the accessible
720 * caret.
722 nsFrameSelection(mozilla::PresShell* aPresShell, nsIContent* aLimiter,
723 bool aAccessibleCaretEnabled);
725 void StartBatchChanges();
727 MOZ_CAN_RUN_SCRIPT_BOUNDARY
729 * @param aReasons potentially multiple of the reasons defined in
730 * nsISelectionListener.idl
732 void EndBatchChanges(int16_t aReasons = nsISelectionListener::NO_REASON);
734 mozilla::PresShell* GetPresShell() const { return mPresShell; }
736 void DisconnectFromPresShell();
737 nsresult ClearNormalSelection();
739 // Table selection support.
740 static nsITableCellLayout* GetCellLayout(const nsIContent* aCellContent);
742 private:
743 ~nsFrameSelection();
745 // TODO: in case an error is returned, it sometimes refers to a programming
746 // error, in other cases to runtime errors. This deserves to be cleaned up.
747 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
748 TakeFocus(nsIContent& aNewFocus, uint32_t aContentOffset,
749 uint32_t aContentEndOffset, CaretAssociateHint aHint,
750 FocusMode aFocusMode);
753 * After moving the caret, its Bidi level is set according to the following
754 * rules:
756 * After moving over a character with left/right arrow, set to the Bidi level
757 * of the last moved over character. After Home and End, set to the paragraph
758 * embedding level. After up/down arrow, PageUp/Down, set to the lower level
759 * of the 2 surrounding characters. After mouse click, set to the level of the
760 * current frame.
762 * The following two methods use GetPrevNextBidiLevels to determine the new
763 * Bidi level. BidiLevelFromMove is called when the caret is moved in response
764 * to a keyboard event
766 * @param aPresShell is the presentation shell
767 * @param aNode is the content node
768 * @param aContentOffset is the new caret position, as an offset into aNode
769 * @param aAmount is the amount of the move that gave the caret its new
770 * position
771 * @param aHint is the hint indicating in what logical direction the caret
772 * moved
774 void BidiLevelFromMove(mozilla::PresShell* aPresShell, nsIContent* aNode,
775 uint32_t aContentOffset, nsSelectionAmount aAmount,
776 CaretAssociateHint aHint);
778 * BidiLevelFromClick is called when the caret is repositioned by clicking the
779 * mouse
781 * @param aNode is the content node
782 * @param aContentOffset is the new caret position, as an offset into aNode
784 void BidiLevelFromClick(nsIContent* aNewFocus, uint32_t aContentOffset);
786 static nsPrevNextBidiLevels GetPrevNextBidiLevels(nsIContent* aNode,
787 uint32_t aContentOffset,
788 CaretAssociateHint aHint,
789 bool aJumpLines);
792 * @param aReasons potentially multiple of the reasons defined in
793 * nsISelectionListener.idl.
795 void SetChangeReasons(int16_t aReasons) {
796 mSelectionChangeReasons = aReasons;
800 * @param aReasons potentially multiple of the reasons defined in
801 * nsISelectionListener.idl.
803 void AddChangeReasons(int16_t aReasons) {
804 mSelectionChangeReasons |= aReasons;
808 * @return potentially multiple of the reasons defined in
809 * nsISelectionListener.idl.
811 int16_t PopChangeReasons() {
812 int16_t retval = mSelectionChangeReasons;
813 mSelectionChangeReasons = nsISelectionListener::NO_REASON;
814 return retval;
817 bool IsUserSelectionReason() const {
818 return (mSelectionChangeReasons &
819 (nsISelectionListener::DRAG_REASON |
820 nsISelectionListener::MOUSEDOWN_REASON |
821 nsISelectionListener::MOUSEUP_REASON |
822 nsISelectionListener::KEYPRESS_REASON)) !=
823 nsISelectionListener::NO_REASON;
826 friend class mozilla::dom::Selection;
827 friend class mozilla::SelectionChangeEventDispatcher;
828 friend struct mozilla::AutoPrepareFocusRange;
830 /*HELPER METHODS*/
831 // Whether MoveCaret should use logical or visual movement,
832 // or follow the bidi.edit.caret_movement_style preference.
833 enum CaretMovementStyle { eLogical, eVisual, eUsePrefStyle };
834 MOZ_CAN_RUN_SCRIPT nsresult MoveCaret(nsDirection aDirection,
835 bool aContinueSelection,
836 nsSelectionAmount aAmount,
837 CaretMovementStyle aMovementStyle);
840 * PeekOffsetForCaretMove() only peek offset for caret move. I.e., won't
841 * change selection ranges nor bidi information.
843 mozilla::Result<nsPeekOffsetStruct, nsresult> PeekOffsetForCaretMove(
844 nsDirection aDirection, bool aContinueSelection,
845 const nsSelectionAmount aAmount, CaretMovementStyle aMovementStyle,
846 const nsPoint& aDesiredCaretPos) const;
849 * CreateRangeExtendedToSomewhere() is common method to implement
850 * CreateRangeExtendedTo*(). This method creates a range extended from
851 * normal selection range.
853 template <typename RangeType>
854 MOZ_CAN_RUN_SCRIPT mozilla::Result<RefPtr<RangeType>, nsresult>
855 CreateRangeExtendedToSomewhere(nsDirection aDirection,
856 const nsSelectionAmount aAmount,
857 CaretMovementStyle aMovementStyle);
860 * IsIntraLineCaretMove() is a helper method for PeekOffsetForCaretMove()
861 * and CreateRangeExtendedToSomwhereFromNormalSelection(). This returns
862 * whether aAmount is intra line move or is crossing hard line break.
863 * This returns error if aMount is not supported by the methods.
865 static mozilla::Result<bool, nsresult> IsIntraLineCaretMove(
866 nsSelectionAmount aAmount) {
867 switch (aAmount) {
868 case eSelectCharacter:
869 case eSelectCluster:
870 case eSelectWord:
871 case eSelectWordNoSpace:
872 case eSelectBeginLine:
873 case eSelectEndLine:
874 return true;
875 case eSelectLine:
876 return false;
877 default:
878 return mozilla::Err(NS_ERROR_FAILURE);
882 void InvalidateDesiredCaretPos(); // do not listen to mDesiredCaretPos.mValue
883 // you must get another.
885 bool IsBatching() const { return mBatching.mCounter > 0; }
887 void SetChangesDuringBatchingFlag() {
888 MOZ_ASSERT(mBatching.mCounter > 0);
890 mBatching.mChangesDuringBatching = true;
893 // nsFrameSelection may get deleted when calling this,
894 // so remember to use nsCOMPtr when needed.
895 MOZ_CAN_RUN_SCRIPT
896 nsresult NotifySelectionListeners(mozilla::SelectionType aSelectionType);
898 static nsresult GetCellIndexes(const nsIContent* aCell, int32_t& aRowIndex,
899 int32_t& aColIndex);
901 static nsIContent* GetFirstCellNodeInRange(const nsRange* aRange);
902 // Returns non-null table if in same table, null otherwise
903 static nsIContent* IsInSameTable(const nsIContent* aContent1,
904 const nsIContent* aContent2);
905 // Might return null
906 static nsIContent* GetParentTable(const nsIContent* aCellNode);
908 ////////////BEGIN nsFrameSelection members
910 RefPtr<mozilla::dom::Selection>
911 mDomSelections[sizeof(mozilla::kPresentSelectionTypes) /
912 sizeof(mozilla::SelectionType)];
914 struct TableSelection {
915 // Get our first range, if its first selected node is a cell. If this does
916 // not return null, then the first node in the returned range is a cell
917 // (according to GetFirstCellNodeInRange).
918 nsRange* GetFirstCellRange(const mozilla::dom::Selection& aNormalSelection);
920 // Get our next range, if its first selected node is a cell. If this does
921 // not return null, then the first node in the returned range is a cell
922 // (according to GetFirstCellNodeInRange).
923 nsRange* GetNextCellRange(const mozilla::dom::Selection& aNormalSelection);
925 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
926 HandleSelection(nsINode* aParentContent, int32_t aContentOffset,
927 mozilla::TableSelectionMode aTarget,
928 mozilla::WidgetMouseEvent* aMouseEvent, bool aDragState,
929 mozilla::dom::Selection& aNormalSelection);
932 * @return the closest inclusive table cell ancestor
933 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of
934 * aContent, if it is actively editable.
936 static nsINode* IsContentInActivelyEditableTableCell(
937 nsPresContext* aContext, nsIContent* aContent);
939 // TODO: annotate this with `MOZ_CAN_RUN_SCRIPT` instead.
940 MOZ_CAN_RUN_SCRIPT_BOUNDARY
941 nsresult SelectBlockOfCells(nsIContent* aStartCell, nsIContent* aEndCell,
942 mozilla::dom::Selection& aNormalSelection);
944 nsresult SelectRowOrColumn(nsIContent* aCellContent,
945 mozilla::dom::Selection& aNormalSelection);
947 MOZ_CAN_RUN_SCRIPT nsresult
948 UnselectCells(const nsIContent* aTable, int32_t aStartRowIndex,
949 int32_t aStartColumnIndex, int32_t aEndRowIndex,
950 int32_t aEndColumnIndex, bool aRemoveOutsideOfCellRange,
951 mozilla::dom::Selection& aNormalSelection);
953 nsCOMPtr<nsINode>
954 mClosestInclusiveTableCellAncestor; // used to snap to table selection
955 nsCOMPtr<nsIContent> mStartSelectedCell;
956 nsCOMPtr<nsIContent> mEndSelectedCell;
957 nsCOMPtr<nsIContent> mAppendStartSelectedCell;
958 nsCOMPtr<nsIContent> mUnselectCellOnMouseUp;
959 mozilla::TableSelectionMode mMode = mozilla::TableSelectionMode::None;
960 int32_t mSelectedCellIndex = 0;
961 bool mDragSelectingCells = false;
963 private:
964 struct MOZ_STACK_CLASS FirstAndLastCell {
965 nsCOMPtr<nsIContent> mFirst;
966 nsCOMPtr<nsIContent> mLast;
969 mozilla::Result<FirstAndLastCell, nsresult>
970 FindFirstAndLastCellOfRowOrColumn(const nsIContent& aCellContent) const;
972 [[nodiscard]] nsresult HandleDragSelecting(
973 mozilla::TableSelectionMode aTarget, nsIContent* aChildContent,
974 const mozilla::WidgetMouseEvent* aMouseEvent,
975 mozilla::dom::Selection& aNormalSelection);
977 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandleMouseUpOrDown(
978 mozilla::TableSelectionMode aTarget, bool aDragState,
979 nsIContent* aChildContent, nsINode* aParentContent,
980 int32_t aContentOffset, const mozilla::WidgetMouseEvent* aMouseEvent,
981 mozilla::dom::Selection& aNormalSelection);
983 class MOZ_STACK_CLASS RowAndColumnRelation;
986 TableSelection mTableSelection;
988 struct MaintainedRange {
990 * Ensure anchor and focus of aNormalSelection are ordered appropriately
991 * relative to the maintained range.
993 MOZ_CAN_RUN_SCRIPT void AdjustNormalSelection(
994 const nsIContent* aContent, int32_t aOffset,
995 mozilla::dom::Selection& aNormalSelection) const;
998 * @param aScrollViewStop see `nsPeekOffsetStruct::mScrollViewStop`.
1000 void AdjustContentOffsets(nsIFrame::ContentOffsets& aOffsets,
1001 bool aScrollViewStop) const;
1003 void MaintainAnchorFocusRange(
1004 const mozilla::dom::Selection& aNormalSelection,
1005 nsSelectionAmount aAmount);
1007 RefPtr<nsRange> mRange;
1008 nsSelectionAmount mAmount = eSelectNoAmount;
1011 MaintainedRange mMaintainedRange;
1013 struct Batching {
1014 uint32_t mCounter = 0;
1015 bool mChangesDuringBatching = false;
1018 Batching mBatching;
1020 struct Limiters {
1021 // Limit selection navigation to a child of this node.
1022 nsCOMPtr<nsIContent> mLimiter;
1023 // Limit selection navigation to a descendant of this node.
1024 nsCOMPtr<nsIContent> mAncestorLimiter;
1027 Limiters mLimiters;
1029 mozilla::PresShell* mPresShell = nullptr;
1030 // Reasons for notifications of selection changing.
1031 // Can be multiple of the reasons defined in nsISelectionListener.idl.
1032 int16_t mSelectionChangeReasons = nsISelectionListener::NO_REASON;
1033 // For visual display purposes.
1034 int16_t mDisplaySelection = nsISelectionController::SELECTION_OFF;
1036 struct Caret {
1037 // Hint to tell if the selection is at the end of this line or beginning of
1038 // next.
1039 CaretAssociateHint mHint = mozilla::CARET_ASSOCIATE_BEFORE;
1040 nsBidiLevel mBidiLevel = BIDI_LEVEL_UNDEFINED;
1042 bool IsVisualMovement(bool aContinueSelection,
1043 CaretMovementStyle aMovementStyle) const;
1046 Caret mCaret;
1048 nsBidiLevel mKbdBidiLevel = NSBIDI_LTR;
1050 class DesiredCaretPos {
1051 public:
1052 // the position requested by the Key Handling for up down
1053 nsresult FetchPos(nsPoint& aDesiredCaretPos,
1054 const mozilla::PresShell& aPresShell,
1055 mozilla::dom::Selection& aNormalSelection) const;
1057 void Set(const nsPoint& aPos);
1059 void Invalidate();
1061 bool mIsSet = false;
1063 private:
1064 nsPoint mValue;
1067 DesiredCaretPos mDesiredCaretPos;
1069 struct DelayedMouseEvent {
1070 bool mIsValid = false;
1071 // These values are not used since they are only valid when mIsValid is
1072 // true, and setting mIsValid always overrides these values.
1073 bool mIsShift = false;
1074 uint32_t mClickCount = 0;
1077 DelayedMouseEvent mDelayedMouseEvent;
1079 bool mDragState = false; // for drag purposes
1080 bool mAccessibleCaretEnabled = false;
1083 #endif /* nsFrameSelection_h___ */