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 "mozilla/Attributes.h"
11 #include "mozilla/EventForwards.h"
12 #include "mozilla/dom/Selection.h"
13 #include "mozilla/TextRange.h"
14 #include "mozilla/UniquePtr.h"
15 #include "nsIFrame.h"
16 #include "nsIContent.h"
17 #include "nsISelectionController.h"
18 #include "nsISelectionListener.h"
19 #include "nsITableCellLayout.h"
20 #include "nsIDOMElement.h"
21 #include "WordMovementType.h"
22 #include "CaretAssociationHint.h"
23 #include "nsBidiPresUtils.h"
24 
25 class nsRange;
26 
27 #define BIDI_LEVEL_UNDEFINED 0x80
28 
29 //----------------------------------------------------------------------
30 
31 // Selection interface
32 
33 struct SelectionDetails {
34 #ifdef NS_BUILD_REFCNT_LOGGING
SelectionDetailsSelectionDetails35   SelectionDetails() { MOZ_COUNT_CTOR(SelectionDetails); }
~SelectionDetailsSelectionDetails36   ~SelectionDetails() { MOZ_COUNT_DTOR(SelectionDetails); }
37 #endif
38   int32_t mStart;
39   int32_t mEnd;
40   mozilla::SelectionType mSelectionType;
41   mozilla::TextRangeStyle mTextRangeStyle;
42   mozilla::UniquePtr<SelectionDetails> mNext;
43 };
44 
45 struct SelectionCustomColors {
46 #ifdef NS_BUILD_REFCNT_LOGGING
SelectionCustomColorsSelectionCustomColors47   SelectionCustomColors() { MOZ_COUNT_CTOR(SelectionCustomColors); }
~SelectionCustomColorsSelectionCustomColors48   ~SelectionCustomColors() { MOZ_COUNT_DTOR(SelectionCustomColors); }
49 #endif
50   mozilla::Maybe<nscolor> mForegroundColor;
51   mozilla::Maybe<nscolor> mBackgroundColor;
52   mozilla::Maybe<nscolor> mAltForegroundColor;
53   mozilla::Maybe<nscolor> mAltBackgroundColor;
54 };
55 
56 class nsIPresShell;
57 
58 /** PeekOffsetStruct is used to group various arguments (both input and output)
59  *  that are passed to nsFrame::PeekOffset(). See below for the description of
60  *  individual arguments.
61  */
62 struct MOZ_STACK_CLASS nsPeekOffsetStruct {
63   nsPeekOffsetStruct(
64       nsSelectionAmount aAmount, nsDirection aDirection, int32_t aStartOffset,
65       nsPoint aDesiredPos, bool aJumpLines, bool aScrollViewStop,
66       bool aIsKeyboardSelect, bool aVisual, bool aExtend,
67       mozilla::EWordMovementType aWordMovementType = mozilla::eDefaultBehavior);
68 
69   // Note: Most arguments (input and output) are only used with certain values
70   // of mAmount. These values are indicated for each argument below.
71   // Arguments with no such indication are used with all values of mAmount.
72 
73   /*** Input arguments ***/
74   // Note: The value of some of the input arguments may be changed upon exit.
75 
76   // mAmount: The type of movement requested (by character, word, line, etc.)
77   nsSelectionAmount mAmount;
78 
79   // mDirection: eDirPrevious or eDirNext.
80   //             * Note for visual bidi movement:
81   //             eDirPrevious means 'left-then-up' if the containing block is
82   //             LTR, 'right-then-up' if it is RTL. eDirNext means
83   //             'right-then-down' if the containing block is LTR,
84   //             'left-then-down' if it is RTL.
85   //             Between paragraphs, eDirPrevious means "go to the visual end of
86   //             the previous paragraph", and eDirNext means "go to the visual
87   //             beginning of the next paragraph". Used with: eSelectCharacter,
88   //             eSelectWord, eSelectLine, eSelectParagraph.
89   nsDirection mDirection;
90 
91   // mStartOffset: Offset into the content of the current frame where the peek
92   // starts.
93   //               Used with: eSelectCharacter, eSelectWord
94   int32_t mStartOffset;
95 
96   // mDesiredPos: The desired inline coordinate for the caret
97   //              (one of .x or .y will be used, depending on line's writing
98   //              mode) Used with: eSelectLine.
99   nsPoint mDesiredPos;
100 
101   // mWordMovementType: An enum that determines whether to prefer the start or
102   // end of a word
103   //                    or to use the default beahvior, which is a combination
104   //                    of direction and the platform-based pref
105   //                    "layout.word_select.eat_space_to_next_word"
106   mozilla::EWordMovementType mWordMovementType;
107 
108   // mJumpLines: Whether to allow jumping across line boundaries.
109   //             Used with: eSelectCharacter, eSelectWord.
110   bool mJumpLines;
111 
112   // mScrollViewStop: Whether to stop when reaching a scroll view boundary.
113   //                  Used with: eSelectCharacter, eSelectWord, eSelectLine.
114   bool mScrollViewStop;
115 
116   // mIsKeyboardSelect: Whether the peeking is done in response to a keyboard
117   // action.
118   //                    Used with: eSelectWord.
119   bool mIsKeyboardSelect;
120 
121   // mVisual: Whether bidi caret behavior is visual (true) or logical (false).
122   //          Used with: eSelectCharacter, eSelectWord, eSelectBeginLine,
123   //          eSelectEndLine.
124   bool mVisual;
125 
126   // mExtend: Whether the selection is being extended or moved.
127   bool mExtend;
128 
129   /*** Output arguments ***/
130 
131   // mResultContent: Content reached as a result of the peek.
132   nsCOMPtr<nsIContent> mResultContent;
133 
134   // mResultFrame: Frame reached as a result of the peek.
135   //               Used with: eSelectCharacter, eSelectWord.
136   nsIFrame* mResultFrame;
137 
138   // mContentOffset: Offset into content reached as a result of the peek.
139   int32_t mContentOffset;
140 
141   // mAttachForward: When the result position is between two frames,
142   //                 indicates which of the two frames the caret should be
143   //                 painted in. false means "the end of the frame logically
144   //                 before the caret", true means "the beginning of the frame
145   //                 logically after the caret". Used with: eSelectLine,
146   //                 eSelectBeginLine, eSelectEndLine.
147   mozilla::CaretAssociationHint mAttach;
148 };
149 
150 struct nsPrevNextBidiLevels {
SetDatansPrevNextBidiLevels151   void SetData(nsIFrame* aFrameBefore, nsIFrame* aFrameAfter,
152                nsBidiLevel aLevelBefore, nsBidiLevel aLevelAfter) {
153     mFrameBefore = aFrameBefore;
154     mFrameAfter = aFrameAfter;
155     mLevelBefore = aLevelBefore;
156     mLevelAfter = aLevelAfter;
157   }
158   nsIFrame* mFrameBefore;
159   nsIFrame* mFrameAfter;
160   nsBidiLevel mLevelBefore;
161   nsBidiLevel mLevelAfter;
162 };
163 
164 namespace mozilla {
165 namespace dom {
166 class Selection;
167 class SelectionChangeListener;
168 }  // namespace dom
169 }  // namespace mozilla
170 class nsIScrollableFrame;
171 
172 /**
173  * Methods which are marked with *unsafe* should be handled with special care.
174  * They may cause nsFrameSelection to be deleted, if strong pointer isn't used,
175  * or they may cause other objects to be deleted.
176  */
177 class nsFrameSelection final {
178  public:
179   typedef mozilla::CaretAssociationHint CaretAssociateHint;
180 
181   /*interfaces for addref and release and queryinterface*/
182 
183   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsFrameSelection)
184   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsFrameSelection)
185 
186   /** Init will initialize the frame selector with the necessary pres shell to
187    *  be used by most of the methods
188    *  @param aShell is the parameter to be used for most of the other calls for
189    * callbacks etc
190    *  @param aLimiter limits the selection to nodes with aLimiter parents
191    *  @param aAccessibleCaretEnabled true if we should enable the accessible
192    * caret.
193    */
194   void Init(nsIPresShell* aShell, nsIContent* aLimiter,
195             bool aAccessibleCaretEnabled);
196 
197   /** HandleClick will take the focus to the new frame at the new offset and
198    *  will either extend the selection from the old anchor, or replace the old
199    * anchor. the old anchor and focus position may also be used to deselect
200    * things
201    *  @param aNewfocus is the content that wants the focus
202    *  @param aContentOffset is the content offset of the parent aNewFocus
203    *  @param aContentOffsetEnd is the content offset of the parent aNewFocus and
204    * is specified different when you need to select to and include both start
205    * and end points
206    *  @param aContinueSelection is the flag that tells the selection to keep the
207    * old anchor point or not.
208    *  @param aMultipleSelection will tell the frame selector to replace /or not
209    * the old selection. cannot coexist with aContinueSelection
210    *  @param aHint will tell the selection which direction geometrically to
211    * actually show the caret on. 1 = end of this line 0 = beginning of this line
212    */
213   /*unsafe*/
214   nsresult HandleClick(nsIContent* aNewFocus, uint32_t aContentOffset,
215                        uint32_t aContentEndOffset, bool aContinueSelection,
216                        bool aMultipleSelection, CaretAssociateHint aHint);
217 
218   /** HandleDrag extends the selection to contain the frame closest to aPoint.
219    *  @param aPresContext is the context to use when figuring out what frame
220    * contains the point.
221    *  @param aFrame is the parent of all frames to use when searching for the
222    * closest frame to the point.
223    *  @param aPoint is relative to aFrame
224    */
225   /*unsafe*/
226   void HandleDrag(nsIFrame* aFrame, const nsPoint& aPoint);
227 
228   /** HandleTableSelection will set selection to a table, cell, etc
229    *   depending on information contained in aFlags
230    *  @param aParentContent is the paretent of either a table or cell that user
231    * clicked or dragged the mouse in
232    *  @param aContentOffset is the offset of the table or cell
233    *  @param aTarget indicates what to select (defined in
234    * nsISelectionPrivate.idl/nsISelectionPrivate.h): TABLESELECTION_CELL      We
235    * should select a cell (content points to the cell) TABLESELECTION_ROW
236    * We should select a row (content points to any cell in row)
237    *    TABLESELECTION_COLUMN    We should select a row (content points to any
238    * cell in column) TABLESELECTION_TABLE     We should select a table (content
239    * points to the table) TABLESELECTION_ALLCELLS  We should select all cells
240    * (content points to any cell in table)
241    *  @param aMouseEvent         passed in so we can get where event occurred
242    * and what keys are pressed
243    */
244   /*unsafe*/
245   nsresult HandleTableSelection(nsINode* aParentContent, int32_t aContentOffset,
246                                 int32_t aTarget,
247                                 mozilla::WidgetMouseEvent* aMouseEvent);
248 
249   /**
250    * Add cell to the selection.
251    *
252    * @param  aCell  [in] HTML td element.
253    */
254   nsresult SelectCellElement(nsIContent* aCell);
255 
256   /**
257    * Add cells to the selection inside of the given cells range.
258    *
259    * @param  aTable             [in] HTML table element
260    * @param  aStartRowIndex     [in] row index where the cells range starts
261    * @param  aStartColumnIndex  [in] column index where the cells range starts
262    * @param  aEndRowIndex       [in] row index where the cells range ends
263    * @param  aEndColumnIndex    [in] column index where the cells range ends
264    */
265   nsresult AddCellsToSelection(nsIContent* aTable, int32_t aStartRowIndex,
266                                int32_t aStartColumnIndex, int32_t aEndRowIndex,
267                                int32_t aEndColumnIndex);
268 
269   /**
270    * Remove cells from selection inside of the given cell range.
271    *
272    * @param  aTable             [in] HTML table element
273    * @param  aStartRowIndex     [in] row index where the cells range starts
274    * @param  aStartColumnIndex  [in] column index where the cells range starts
275    * @param  aEndRowIndex       [in] row index where the cells range ends
276    * @param  aEndColumnIndex    [in] column index where the cells range ends
277    */
278   nsresult RemoveCellsFromSelection(nsIContent* aTable, int32_t aStartRowIndex,
279                                     int32_t aStartColumnIndex,
280                                     int32_t aEndRowIndex,
281                                     int32_t aEndColumnIndex);
282 
283   /**
284    * Remove cells from selection outside of the given cell range.
285    *
286    * @param  aTable             [in] HTML table element
287    * @param  aStartRowIndex     [in] row index where the cells range starts
288    * @param  aStartColumnIndex  [in] column index where the cells range starts
289    * @param  aEndRowIndex       [in] row index where the cells range ends
290    * @param  aEndColumnIndex    [in] column index where the cells range ends
291    */
292   nsresult RestrictCellsToSelection(nsIContent* aTable, int32_t aStartRowIndex,
293                                     int32_t aStartColumnIndex,
294                                     int32_t aEndRowIndex,
295                                     int32_t aEndColumnIndex);
296 
297   /** StartAutoScrollTimer is responsible for scrolling frames so that
298    *  aPoint is always visible, and for selecting any frame that contains
299    *  aPoint. The timer will also reset itself to fire again if we have
300    *  not scrolled to the end of the document.
301    *  @param aFrame is the outermost frame to use when searching for
302    *  the closest frame for the point, i.e. the frame that is capturing
303    *  the mouse
304    *  @param aPoint is relative to aFrame.
305    *  @param aDelay is the timer's interval.
306    */
307   /*unsafe*/
308   nsresult StartAutoScrollTimer(nsIFrame* aFrame, const nsPoint& aPoint,
309                                 uint32_t aDelay);
310 
311   /** StopAutoScrollTimer stops any active auto scroll timer.
312    */
313   void StopAutoScrollTimer();
314 
315   /** Lookup Selection
316    *  returns in frame coordinates the selection beginning and ending with the
317    * type of selection given
318    * @param aContent is the content asking
319    * @param aContentOffset is the starting content boundary
320    * @param aContentLength is the length of the content piece asking
321    * @param aSlowCheck will check using slow method with no shortcuts
322    */
323   mozilla::UniquePtr<SelectionDetails> LookUpSelection(nsIContent* aContent,
324                                                        int32_t aContentOffset,
325                                                        int32_t aContentLength,
326                                                        bool aSlowCheck) const;
327 
328   /** SetDragState(bool);
329    *  sets the drag state to aState for resons of drag state.
330    * @param aState is the new state of drag
331    */
332   /*unsafe*/
333   void SetDragState(bool aState);
334 
335   /** GetDragState(bool *);
336    *  gets the drag state to aState for resons of drag state.
337    * @param aState will hold the state of drag
338    */
GetDragState()339   bool GetDragState() const { return mDragState; }
340 
341   /**
342     if we are in table cell selection mode. aka ctrl click in table cell
343    */
GetTableCellSelection()344   bool GetTableCellSelection() const { return mSelectingTableCellMode != 0; }
ClearTableCellSelection()345   void ClearTableCellSelection() { mSelectingTableCellMode = 0; }
346 
347   /** GetSelection
348    * no query interface for selection. must use this method now.
349    * @param aSelectionType The selection type what you want.
350    */
351   mozilla::dom::Selection* GetSelection(
352       mozilla::SelectionType aSelectionType) const;
353 
354   /**
355    * ScrollSelectionIntoView scrolls a region of the selection,
356    * so that it is visible in the scrolled view.
357    *
358    * @param aSelectionType the selection to scroll into view.
359    * @param aRegion the region inside the selection to scroll into view.
360    * @param aFlags the scroll flags.  Valid bits include:
361    * SCROLL_SYNCHRONOUS: when set, scrolls the selection into view
362    * before returning. If not set, posts a request which is processed
363    * at some point after the method returns.
364    * SCROLL_FIRST_ANCESTOR_ONLY: if set, only the first ancestor will be
365    * scrolled into view.
366    *
367    */
368   /*unsafe*/
369   nsresult ScrollSelectionIntoView(mozilla::SelectionType aSelectionType,
370                                    SelectionRegion aRegion,
371                                    int16_t aFlags) const;
372 
373   /** RepaintSelection repaints the selected frames that are inside the
374    * selection specified by aSelectionType.
375    * @param aSelectionType The selection type what you want to repaint.
376    */
377   nsresult RepaintSelection(mozilla::SelectionType aSelectionType);
378 
379   /** GetFrameForNodeOffset given a node and its child offset, return the
380    * nsIFrame and the offset into that frame.
381    * @param aNode input parameter for the node to look at
382    * @param aOffset offset into above node.
383    * @param aReturnOffset will contain offset into frame.
384    */
385   nsIFrame* GetFrameForNodeOffset(nsIContent* aNode, int32_t aOffset,
386                                   CaretAssociateHint aHint,
387                                   int32_t* aReturnOffset) const;
388 
389   /**
390    * Scrolling then moving caret placement code in common to text areas and
391    * content areas should be located in the implementer
392    * This method will accept the following parameters and perform the scroll
393    * and caret movement.  It remains for the caller to call the final
394    * ScrollCaretIntoView if that called wants to be sure the caret is always
395    * visible.
396    *
397    * @param aForward if true, scroll forward if not scroll backward
398    * @param aExtend  if true, extend selection to the new point
399    * @param aScrollableFrame the frame to scroll
400    */
401   /*unsafe*/
402   void CommonPageMove(bool aForward, bool aExtend,
403                       nsIScrollableFrame* aScrollableFrame);
404 
SetHint(CaretAssociateHint aHintRight)405   void SetHint(CaretAssociateHint aHintRight) { mHint = aHintRight; }
GetHint()406   CaretAssociateHint GetHint() const { return mHint; }
407 
408   /**
409    * SetCaretBidiLevel sets the caret bidi level.
410    * @param aLevel the caret bidi level
411    */
412   void SetCaretBidiLevel(nsBidiLevel aLevel);
413 
414   /**
415    * GetCaretBidiLevel gets the caret bidi level.
416    */
417   nsBidiLevel GetCaretBidiLevel() const;
418 
419   /**
420    * UndefineCaretBidiLevel sets the caret bidi level to "undefined".
421    */
422   void UndefineCaretBidiLevel();
423 
424   /** PhysicalMove will generally be called from the nsiselectioncontroller
425    * implementations. the effect being the selection will move one unit
426    * 'aAmount' in the given aDirection.
427    * @param aDirection  the direction to move the selection
428    * @param aAmount     amount of movement (char/line; word/page; eol/doc)
429    * @param aExtend     continue selection
430    */
431   /*unsafe*/
432   nsresult PhysicalMove(int16_t aDirection, int16_t aAmount, bool aExtend);
433 
434   /** CharacterMove will generally be called from the nsiselectioncontroller
435    * implementations. the effect being the selection will move one character
436    * left or right.
437    * @param aForward move forward in document.
438    * @param aExtend continue selection
439    */
440   /*unsafe*/
441   nsresult CharacterMove(bool aForward, bool aExtend);
442 
443   /** CharacterExtendForDelete extends the selection forward (logically) to
444    * the next character cell, so that the selected cell can be deleted.
445    */
446   /*unsafe*/
447   nsresult CharacterExtendForDelete();
448 
449   /** CharacterExtendForBackspace extends the selection backward (logically) to
450    * the previous character cell, so that the selected cell can be deleted.
451    */
452   /*unsafe*/
453   nsresult CharacterExtendForBackspace();
454 
455   /** WordMove will generally be called from the nsiselectioncontroller
456    * implementations. the effect being the selection will move one word left or
457    * right.
458    * @param aForward move forward in document.
459    * @param aExtend continue selection
460    */
461   /*unsafe*/
462   nsresult WordMove(bool aForward, bool aExtend);
463 
464   /** WordExtendForDelete extends the selection backward or forward (logically)
465    * to the next word boundary, so that the selected word can be deleted.
466    * @param aForward select forward in document.
467    */
468   /*unsafe*/
469   nsresult WordExtendForDelete(bool aForward);
470 
471   /** LineMove will generally be called from the nsiselectioncontroller
472    * implementations. the effect being the selection will move one line up or
473    * down.
474    * @param aForward move forward in document.
475    * @param aExtend continue selection
476    */
477   /*unsafe*/
478   nsresult LineMove(bool aForward, bool aExtend);
479 
480   /** IntraLineMove will generally be called from the nsiselectioncontroller
481    * implementations. the effect being the selection will move to beginning or
482    * end of line
483    * @param aForward move forward in document.
484    * @param aExtend continue selection
485    */
486   /*unsafe*/
487   nsresult IntraLineMove(bool aForward, bool aExtend);
488 
489   /** Select All will generally be called from the nsiselectioncontroller
490    * implementations. it will select the whole doc
491    */
492   /*unsafe*/
493   nsresult SelectAll();
494 
495   /** Sets/Gets The display selection enum.
496    */
SetDisplaySelection(int16_t aState)497   void SetDisplaySelection(int16_t aState) { mDisplaySelection = aState; }
GetDisplaySelection()498   int16_t GetDisplaySelection() const { return mDisplaySelection; }
499 
500   /** This method can be used to store the data received during a MouseDown
501    *  event so that we can place the caret during the MouseUp event.
502    * @aMouseEvent the event received by the selection MouseDown
503    *  handling method. A nullptr value can be use to tell this method
504    *  that any data is storing is no longer valid.
505    */
506   void SetDelayedCaretData(mozilla::WidgetMouseEvent* aMouseEvent);
507 
508   /** Get the delayed MouseDown event data necessary to place the
509    *  caret during MouseUp processing.
510    * @return a pointer to the event received
511    *  by the selection during MouseDown processing. It can be nullptr
512    *  if the data is no longer valid.
513    */
HasDelayedCaretData()514   bool HasDelayedCaretData() { return mDelayedMouseEventValid; }
IsShiftDownInDelayedCaretData()515   bool IsShiftDownInDelayedCaretData() {
516     NS_ASSERTION(mDelayedMouseEventValid, "No valid delayed caret data");
517     return mDelayedMouseEventIsShift;
518   }
GetClickCountInDelayedCaretData()519   uint32_t GetClickCountInDelayedCaretData() {
520     NS_ASSERTION(mDelayedMouseEventValid, "No valid delayed caret data");
521     return mDelayedMouseEventClickCount;
522   }
523 
MouseDownRecorded()524   bool MouseDownRecorded() {
525     return !GetDragState() && HasDelayedCaretData() &&
526            GetClickCountInDelayedCaretData() < 2;
527   }
528 
529   /** Get the content node that limits the selection
530    *  When searching up a nodes for parents, as in a text edit field
531    *    in an browser page, we must stop at this node else we reach into the
532    *    parent page, which is very bad!
533    */
GetLimiter()534   nsIContent* GetLimiter() const { return mLimiter; }
535 
GetAncestorLimiter()536   nsIContent* GetAncestorLimiter() const { return mAncestorLimiter; }
537   /*unsafe*/
538   void SetAncestorLimiter(nsIContent* aLimiter);
539 
540   /** This will tell the frame selection that a double click has been pressed
541    *  so it can track abort future drags if inside the same selection
542    *  @aDoubleDown has the double click down happened
543    */
SetMouseDoubleDown(bool aDoubleDown)544   void SetMouseDoubleDown(bool aDoubleDown) {
545     mMouseDoubleDownState = aDoubleDown;
546   }
547 
548   /** This will return whether the double down flag was set.
549    *  @return whether the double down flag was set
550    */
GetMouseDoubleDown()551   bool GetMouseDoubleDown() const { return mMouseDoubleDownState; }
552 
553   /**
554    * GetPrevNextBidiLevels will return the frames and associated Bidi levels of
555    * the characters logically before and after a (collapsed) selection.
556    *  @param aNode is the node containing the selection
557    *  @param aContentOffset is the offset of the selection in the node
558    *  @param aJumpLines If true, look across line boundaries.
559    *                    If false, behave as if there were base-level frames at
560    * line edges.
561    *
562    *  @return A struct holding the before/after frame and the before/after
563    * level.
564    *
565    *  At the beginning and end of each line there is assumed to be a frame with
566    *   Bidi level equal to the paragraph embedding level.
567    *  In these cases the before frame and after frame respectively will be
568    *   nullptr.
569    */
570   nsPrevNextBidiLevels GetPrevNextBidiLevels(nsIContent* aNode,
571                                              uint32_t aContentOffset,
572                                              bool aJumpLines) const;
573 
574   /** GetFrameFromLevel will scan in a given direction
575    *   until it finds a frame with a Bidi level less than or equal to a given
576    * level. It will return the last frame before this.
577    *  @param aPresContext is the context to use
578    *  @param aFrameIn is the frame to start from
579    *  @param aDirection is the direction to scan
580    *  @param aBidiLevel is the level to search for
581    *  @param aFrameOut will hold the frame returned
582    */
583   nsresult GetFrameFromLevel(nsIFrame* aFrameIn, nsDirection aDirection,
584                              nsBidiLevel aBidiLevel,
585                              nsIFrame** aFrameOut) const;
586 
587   /**
588    * MaintainSelection will track the current selection as being "sticky".
589    * Dragging or extending selection will never allow for a subset
590    * (or the whole) of the maintained selection to become unselected.
591    * Primary use: double click selecting then dragging on second click
592    * @param aAmount the initial amount of text selected (word, line or
593    * paragraph). For "line", use eSelectBeginLine.
594    */
595   nsresult MaintainSelection(nsSelectionAmount aAmount = eSelectNoAmount);
596 
597   nsresult ConstrainFrameAndPointToAnchorSubtree(nsIFrame* aFrame,
598                                                  const nsPoint& aPoint,
599                                                  nsIFrame** aRetFrame,
600                                                  nsPoint& aRetPoint);
601 
602   nsFrameSelection();
603 
604   void StartBatchChanges();
605   void EndBatchChanges(int16_t aReason = nsISelectionListener::NO_REASON);
606 
607   /*unsafe*/
608   nsresult DeleteFromDocument();
609 
GetShell()610   nsIPresShell* GetShell() const { return mShell; }
611 
612   void DisconnectFromPresShell();
613   nsresult ClearNormalSelection();
614 
615  private:
616   ~nsFrameSelection();
617 
618   nsresult TakeFocus(nsIContent* aNewFocus, uint32_t aContentOffset,
619                      uint32_t aContentEndOffset, CaretAssociateHint aHint,
620                      bool aContinueSelection, bool aMultipleSelection);
621 
622   void BidiLevelFromMove(nsIPresShell* aPresShell, nsIContent* aNode,
623                          uint32_t aContentOffset, nsSelectionAmount aAmount,
624                          CaretAssociateHint aHint);
625   void BidiLevelFromClick(nsIContent* aNewFocus, uint32_t aContentOffset);
626   nsPrevNextBidiLevels GetPrevNextBidiLevels(nsIContent* aNode,
627                                              uint32_t aContentOffset,
628                                              CaretAssociateHint aHint,
629                                              bool aJumpLines) const;
630 
631   bool AdjustForMaintainedSelection(nsIContent* aContent, int32_t aOffset);
632 
633   // post and pop reasons for notifications. we may stack these later
PostReason(int16_t aReason)634   void PostReason(int16_t aReason) { mSelectionChangeReason = aReason; }
PopReason()635   int16_t PopReason() {
636     int16_t retval = mSelectionChangeReason;
637     mSelectionChangeReason = nsISelectionListener::NO_REASON;
638     return retval;
639   }
IsUserSelectionReason()640   bool IsUserSelectionReason() const {
641     return (mSelectionChangeReason & (nsISelectionListener::DRAG_REASON |
642                                       nsISelectionListener::MOUSEDOWN_REASON |
643                                       nsISelectionListener::MOUSEUP_REASON |
644                                       nsISelectionListener::KEYPRESS_REASON)) !=
645            nsISelectionListener::NO_REASON;
646   }
647 
648   friend class mozilla::dom::Selection;
649   friend class mozilla::dom::SelectionChangeListener;
650   friend struct mozilla::AutoPrepareFocusRange;
651 #ifdef DEBUG
652   void printSelection();  // for debugging
653 #endif                    /* DEBUG */
654 
655   void ResizeBuffer(uint32_t aNewBufSize);
656 
657   /*HELPER METHODS*/
658   // Whether MoveCaret should use logical or visual movement,
659   // or follow the bidi.edit.caret_movement_style preference.
660   enum CaretMovementStyle { eLogical, eVisual, eUsePrefStyle };
661   nsresult MoveCaret(nsDirection aDirection, bool aContinueSelection,
662                      nsSelectionAmount aAmount,
663                      CaretMovementStyle aMovementStyle);
664 
665   nsresult FetchDesiredPos(nsPoint& aDesiredPos);  // the position requested by
666                                                    // the Key Handling for up
667                                                    // down
668   void
669   InvalidateDesiredPos();  // do not listen to mDesiredPos you must get another.
670   void SetDesiredPos(nsPoint aPos);  // set the mDesiredPos
671 
GetBatching()672   uint32_t GetBatching() const { return mBatching; }
GetNotifyFrames()673   bool GetNotifyFrames() const { return mNotifyFrames; }
674   void SetDirty(bool aDirty = true) {
675     if (mBatching) mChangesDuringBatching = aDirty;
676   }
677 
678   // nsFrameSelection may get deleted when calling this,
679   // so remember to use nsCOMPtr when needed.
680   nsresult NotifySelectionListeners(mozilla::SelectionType aSelectionType);
681   // Update the selection cache on repaint when the
682   // selection being repainted is not empty.
683   nsresult UpdateSelectionCacheOnRepaintSelection(
684       mozilla::dom::Selection* aSel);
685 
686   // Table selection support.
687   nsITableCellLayout* GetCellLayout(nsIContent* aCellContent) const;
688 
689   nsresult SelectBlockOfCells(nsIContent* aStartNode, nsIContent* aEndNode);
690   nsresult SelectRowOrColumn(nsIContent* aCellContent, uint32_t aTarget);
691   nsresult UnselectCells(nsIContent* aTable, int32_t aStartRowIndex,
692                          int32_t aStartColumnIndex, int32_t aEndRowIndex,
693                          int32_t aEndColumnIndex,
694                          bool aRemoveOutsideOfCellRange);
695 
696   nsresult GetCellIndexes(nsIContent* aCell, int32_t& aRowIndex,
697                           int32_t& aColIndex);
698 
699   // Get our first range, if its first selected node is a cell.  If this does
700   // not return null, then the first node in the returned range is a cell
701   // (according to GetFirstCellNodeInRange).
702   nsRange* GetFirstCellRange();
703   // Get our next range, if its first selected node is a cell.  If this does
704   // not return null, then the first node in the returned range is a cell
705   // (according to GetFirstCellNodeInRange).
706   nsRange* GetNextCellRange();
707   nsIContent* GetFirstCellNodeInRange(nsRange* aRange) const;
708   // Returns non-null table if in same table, null otherwise
709   nsIContent* IsInSameTable(nsIContent* aContent1, nsIContent* aContent2) const;
710   // Might return null
711   nsIContent* GetParentTable(nsIContent* aCellNode) const;
712   nsresult CreateAndAddRange(nsINode* aContainer, int32_t aOffset);
713 
714   ////////////BEGIN nsFrameSelection members
715 
716   RefPtr<mozilla::dom::Selection>
717       mDomSelections[sizeof(mozilla::kPresentSelectionTypes) /
718                      sizeof(mozilla::SelectionType)];
719 
720   nsCOMPtr<nsINode> mCellParent;  // used to snap to table selection
721   nsCOMPtr<nsIContent> mStartSelectedCell;
722   nsCOMPtr<nsIContent> mEndSelectedCell;
723   nsCOMPtr<nsIContent> mAppendStartSelectedCell;
724   nsCOMPtr<nsIContent> mUnselectCellOnMouseUp;
725   int32_t mSelectingTableCellMode = 0;
726   int32_t mSelectedCellIndex = 0;
727 
728   // maintain selection
729   RefPtr<nsRange> mMaintainRange;
730   nsSelectionAmount mMaintainedAmount = eSelectNoAmount;
731 
732   // batching
733   int32_t mBatching = 0;
734 
735   // Limit selection navigation to a child of this node.
736   nsCOMPtr<nsIContent> mLimiter;
737   // Limit selection navigation to a descendant of this node.
738   nsCOMPtr<nsIContent> mAncestorLimiter;
739 
740   nsIPresShell* mShell = nullptr;
741   // Reason for notifications of selection changing.
742   int16_t mSelectionChangeReason = nsISelectionListener::NO_REASON;
743   // For visual display purposes.
744   int16_t mDisplaySelection = nsISelectionController::SELECTION_OFF;
745 
746   // Hint to tell if the selection is at the end of this line or beginning of
747   // next.
748   CaretAssociateHint mHint = mozilla::CARET_ASSOCIATE_BEFORE;
749   nsBidiLevel mCaretBidiLevel = BIDI_LEVEL_UNDEFINED;
750   nsBidiLevel mKbdBidiLevel = NSBIDI_LTR;
751 
752   nsPoint mDesiredPos;
753   bool mDelayedMouseEventValid = false;
754   // These values are not used since they are only valid when
755   // mDelayedMouseEventValid is true, and setting mDelayedMouseEventValid
756   // always overrides these values.
757   uint32_t mDelayedMouseEventClickCount = 0;
758   bool mDelayedMouseEventIsShift = false;
759 
760   bool mChangesDuringBatching = false;
761   bool mNotifyFrames = true;
762   bool mDragSelectingCells = false;
763   bool mDragState = false;             // for drag purposes
764   bool mMouseDoubleDownState = false;  // has the doubleclick down happened
765   bool mDesiredPosSet = false;
766   bool mAccessibleCaretEnabled = false;
767 
768   int8_t mCaretMovementStyle = 0;
769 
770   static bool sSelectionEventsEnabled;
771   static bool sSelectionEventsOnTextControlsEnabled;
772 };
773 
774 #endif /* nsFrameSelection_h___ */
775