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