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"
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"
28 #define BIDI_LEVEL_UNDEFINED 0x80
30 //----------------------------------------------------------------------
32 // Selection interface
34 struct SelectionDetails
{
36 : mStart(), mEnd(), mSelectionType(mozilla::SelectionType::eInvalid
) {
37 MOZ_COUNT_CTOR(SelectionDetails
);
39 MOZ_COUNTED_DTOR(SelectionDetails
)
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
)
53 mozilla::Maybe
<nscolor
> mForegroundColor
;
54 mozilla::Maybe
<nscolor
> mBackgroundColor
;
55 mozilla::Maybe
<nscolor
> mAltForegroundColor
;
56 mozilla::Maybe
<nscolor
> mAltBackgroundColor
;
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
{
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.
144 // Whether the selection is being extended or moved.
147 // If true, the offset has to end up in an editable node, otherwise we'll keep
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
;
188 class SelectionChangeEventDispatcher
;
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
{
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
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
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
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
);
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
341 * @param aPoint is relative to aFrame.
343 * @param aDelay is the timer's interval.
346 nsresult
StartAutoScrollTimer(nsIFrame
* aFrame
, const nsPoint
& aPoint
,
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
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
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
,
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
,
501 * CharacterMove will generally be called from the nsiselectioncontroller
502 * implementations. the effect being the selection will move one character
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
,
512 * WordMove will generally be called from the nsiselectioncontroller
513 * implementations. the effect being the selection will move one word left or
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
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
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
,
543 * CreateRangeExtendedToNextGraphemeClusterBoundary() returns range which is
544 * extended from normal selection range to start of next grapheme cluster
547 template <typename RangeType
>
548 MOZ_CAN_RUN_SCRIPT
mozilla::Result
<RefPtr
<RangeType
>, nsresult
>
549 CreateRangeExtendedToNextGraphemeClusterBoundary() {
550 return CreateRangeExtendedToSomewhere
<RangeType
>(eDirNext
, eSelectCluster
,
555 * CreateRangeExtendedToPreviousCharacterBoundary() returns range which is
556 * extended from normal selection range to start of previous character
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
,
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
,
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
,
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
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
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
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
717 * @param aLimiter limits the selection to nodes with aLimiter parents
719 * @param aAccessibleCaretEnabled true if we should enable the accessible
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
);
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
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
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
771 * @param aHint is the hint indicating in what logical direction the caret
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
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
,
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
;
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
;
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
) {
868 case eSelectCharacter
:
871 case eSelectWordNoSpace
:
872 case eSelectBeginLine
:
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.
896 nsresult
NotifySelectionListeners(mozilla::SelectionType aSelectionType
);
898 static nsresult
GetCellIndexes(const nsIContent
* aCell
, int32_t& aRowIndex
,
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
);
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
);
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;
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
;
1014 uint32_t mCounter
= 0;
1015 bool mChangesDuringBatching
= false;
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
;
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
;
1037 // Hint to tell if the selection is at the end of this line or beginning of
1039 CaretAssociateHint mHint
= mozilla::CARET_ASSOCIATE_BEFORE
;
1040 nsBidiLevel mBidiLevel
= BIDI_LEVEL_UNDEFINED
;
1042 bool IsVisualMovement(bool aContinueSelection
,
1043 CaretMovementStyle aMovementStyle
) const;
1048 nsBidiLevel mKbdBidiLevel
= NSBIDI_LTR
;
1050 class DesiredCaretPos
{
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
);
1061 bool mIsSet
= false;
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___ */