Bug 1698238 return default dictionary from GetUserMediaRequest#getConstraints() if...
[gecko.git] / dom / base / Selection.h
blob0c8821b4c45cade06037acaec95d2789f81b946d
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_Selection_h__
8 #define mozilla_Selection_h__
10 #include "mozilla/dom/StyledRange.h"
11 #include "mozilla/AutoRestore.h"
12 #include "mozilla/EventForwards.h"
13 #include "mozilla/PresShellForwards.h"
14 #include "mozilla/RangeBoundary.h"
15 #include "mozilla/SelectionChangeEventDispatcher.h"
16 #include "mozilla/UniquePtr.h"
17 #include "mozilla/WeakPtr.h"
18 #include "nsDirection.h"
19 #include "nsISelectionController.h"
20 #include "nsISelectionListener.h"
21 #include "nsRange.h"
22 #include "nsTArrayForwardDeclare.h"
23 #include "nsThreadUtils.h"
24 #include "nsWeakReference.h"
25 #include "nsWrapperCache.h"
27 struct CachedOffsetForFrame;
28 class AutoScroller;
29 class nsIFrame;
30 class nsFrameSelection;
31 class nsPIDOMWindowOuter;
32 struct SelectionDetails;
33 struct SelectionCustomColors;
34 class nsCopySupport;
35 class nsHTMLCopyEncoder;
36 class nsPresContext;
37 struct nsPoint;
38 struct nsRect;
40 namespace mozilla {
41 class AccessibleCaretEventHub;
42 class ErrorResult;
43 class HTMLEditor;
44 class PostContentIterator;
45 enum class TableSelectionMode : uint32_t;
46 struct AutoPrepareFocusRange;
47 namespace dom {
48 class DocGroup;
49 } // namespace dom
50 } // namespace mozilla
52 namespace mozilla {
54 namespace dom {
56 // Note, the ownership of mozilla::dom::Selection depends on which way the
57 // object is created. When nsFrameSelection has created Selection,
58 // addreffing/releasing the Selection object is aggregated to nsFrameSelection.
59 // Otherwise normal addref/release is used. This ensures that nsFrameSelection
60 // is never deleted before its Selections.
61 class Selection final : public nsSupportsWeakReference,
62 public nsWrapperCache,
63 public SupportsWeakPtr {
64 protected:
65 virtual ~Selection();
67 public:
68 /**
69 * @param aFrameSelection can be nullptr.
71 explicit Selection(SelectionType aSelectionType,
72 nsFrameSelection* aFrameSelection);
74 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
75 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Selection)
77 // match this up with EndbatchChanges. will stop ui updates while multiple
78 // selection methods are called
79 void StartBatchChanges();
81 // match this up with StartBatchChanges
82 void EndBatchChanges(int16_t aReason = nsISelectionListener::NO_REASON);
84 /**
85 * NotifyAutoCopy() starts to notify AutoCopyListener of selection changes.
87 void NotifyAutoCopy() {
88 MOZ_ASSERT(mSelectionType == SelectionType::eNormal);
90 mNotifyAutoCopy = true;
93 /**
94 * MaybeNotifyAccessibleCaretEventHub() starts to notify
95 * AccessibleCaretEventHub of selection change if aPresShell has it.
97 void MaybeNotifyAccessibleCaretEventHub(PresShell* aPresShell);
99 /**
100 * StopNotifyingAccessibleCaretEventHub() stops notifying
101 * AccessibleCaretEventHub of selection change.
103 void StopNotifyingAccessibleCaretEventHub();
106 * EnableSelectionChangeEvent() starts to notify
107 * SelectionChangeEventDispatcher of selection change to dispatch a
108 * selectionchange event at every selection change.
110 void EnableSelectionChangeEvent() {
111 if (!mSelectionChangeEventDispatcher) {
112 mSelectionChangeEventDispatcher = new SelectionChangeEventDispatcher();
116 // Required for WebIDL bindings, see
117 // https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings#Adding_WebIDL_bindings_to_a_class.
118 Document* GetParentObject() const;
120 DocGroup* GetDocGroup() const;
122 // utility methods for scrolling the selection into view
123 nsPresContext* GetPresContext() const;
124 PresShell* GetPresShell() const;
125 nsFrameSelection* GetFrameSelection() const { return mFrameSelection; }
126 // Returns a rect containing the selection region, and frame that that
127 // position is relative to. For SELECTION_ANCHOR_REGION or
128 // SELECTION_FOCUS_REGION the rect is a zero-width rectangle. For
129 // SELECTION_WHOLE_SELECTION the rect contains both the anchor and focus
130 // region rects.
131 nsIFrame* GetSelectionAnchorGeometry(SelectionRegion aRegion, nsRect* aRect);
132 // Returns the position of the region (SELECTION_ANCHOR_REGION or
133 // SELECTION_FOCUS_REGION only), and frame that that position is relative to.
134 // The 'position' is a zero-width rectangle.
135 nsIFrame* GetSelectionEndPointGeometry(SelectionRegion aRegion,
136 nsRect* aRect);
138 nsresult PostScrollSelectionIntoViewEvent(SelectionRegion aRegion,
139 int32_t aFlags,
140 ScrollAxis aVertical,
141 ScrollAxis aHorizontal);
142 enum {
143 SCROLL_SYNCHRONOUS = 1 << 1,
144 SCROLL_FIRST_ANCESTOR_ONLY = 1 << 2,
145 SCROLL_DO_FLUSH =
146 1 << 3, // only matters if SCROLL_SYNCHRONOUS is passed too
147 SCROLL_OVERFLOW_HIDDEN = 1 << 5,
148 SCROLL_FOR_CARET_MOVE = 1 << 6
150 // If aFlags doesn't contain SCROLL_SYNCHRONOUS, then we'll flush when
151 // the scroll event fires so we make sure to scroll to the right place.
152 // Otherwise, if SCROLL_DO_FLUSH is also in aFlags, then this method will
153 // flush layout and you MUST hold a strong ref on 'this' for the duration
154 // of this call. This might destroy arbitrary layout objects.
155 MOZ_CAN_RUN_SCRIPT nsresult
156 ScrollIntoView(SelectionRegion aRegion, ScrollAxis aVertical = ScrollAxis(),
157 ScrollAxis aHorizontal = ScrollAxis(), int32_t aFlags = 0);
159 private:
160 static bool IsUserSelectionCollapsed(
161 const nsRange& aRange, nsTArray<RefPtr<nsRange>>& aTempRangesToAdd);
163 * https://w3c.github.io/selection-api/#selectstart-event.
165 enum class DispatchSelectstartEvent {
167 Maybe,
171 * See `AddRangesForSelectableNodes`.
173 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult AddRangesForUserSelectableNodes(
174 nsRange* aRange, int32_t* aOutIndex,
175 const DispatchSelectstartEvent aDispatchSelectstartEvent);
178 * Adds aRange to this Selection. If mUserInitiated is true,
179 * then aRange is first scanned for -moz-user-select:none nodes and split up
180 * into multiple ranges to exclude those before adding the resulting ranges
181 * to this Selection.
183 * @param aOutIndex points to the range last added, if at least one was added.
184 * If aRange is already contained, it points to the range
185 * containing it. -1 if mStyledRanges.mRanges was empty and
186 * no range was added.
188 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult AddRangesForSelectableNodes(
189 nsRange* aRange, int32_t* aOutIndex,
190 DispatchSelectstartEvent aDispatchSelectstartEvent);
192 public:
193 nsresult RemoveCollapsedRanges();
194 nsresult Clear(nsPresContext* aPresContext);
195 MOZ_CAN_RUN_SCRIPT nsresult CollapseInLimiter(nsINode* aContainer,
196 int32_t aOffset) {
197 if (!aContainer) {
198 return NS_ERROR_INVALID_ARG;
200 return CollapseInLimiter(RawRangeBoundary(aContainer, aOffset));
202 MOZ_CAN_RUN_SCRIPT nsresult
203 CollapseInLimiter(const RawRangeBoundary& aPoint) {
204 ErrorResult result;
205 CollapseInLimiter(aPoint, result);
206 return result.StealNSResult();
208 MOZ_CAN_RUN_SCRIPT void CollapseInLimiter(const RawRangeBoundary& aPoint,
209 ErrorResult& aRv) {
210 CollapseInternal(InLimiter::eYes, aPoint, aRv);
213 MOZ_CAN_RUN_SCRIPT nsresult Extend(nsINode* aContainer, int32_t aOffset);
216 * See mStyledRanges.mRanges.
218 nsRange* GetRangeAt(int32_t aIndex) const;
220 // Get the anchor-to-focus range if we don't care which end is
221 // anchor and which end is focus.
222 const nsRange* GetAnchorFocusRange() const { return mAnchorFocusRange; }
224 nsDirection GetDirection() const { return mDirection; }
226 void SetDirection(nsDirection aDir) { mDirection = aDir; }
227 MOZ_CAN_RUN_SCRIPT nsresult SetAnchorFocusToRange(nsRange* aRange);
229 MOZ_CAN_RUN_SCRIPT void ReplaceAnchorFocusRange(nsRange* aRange);
231 void AdjustAnchorFocusForMultiRange(nsDirection aDirection);
233 nsIFrame* GetPrimaryFrameForAnchorNode() const;
234 nsIFrame* GetPrimaryFrameForFocusNode(bool aVisual,
235 int32_t* aOffsetUsed = nullptr) const;
237 UniquePtr<SelectionDetails> LookUpSelection(
238 nsIContent* aContent, int32_t aContentOffset, int32_t aContentLength,
239 UniquePtr<SelectionDetails> aDetailsHead, SelectionType aSelectionType,
240 bool aSlowCheck);
242 NS_IMETHOD Repaint(nsPresContext* aPresContext);
244 MOZ_CAN_RUN_SCRIPT
245 nsresult StartAutoScrollTimer(nsIFrame* aFrame, const nsPoint& aPoint,
246 uint32_t aDelayInMs);
248 nsresult StopAutoScrollTimer();
250 JSObject* WrapObject(JSContext* aCx,
251 JS::Handle<JSObject*> aGivenProto) override;
253 // WebIDL methods
254 nsINode* GetAnchorNode(CallerType aCallerType = CallerType::System) const {
255 const RangeBoundary& anchor = AnchorRef();
256 nsINode* anchorNode = anchor.IsSet() ? anchor.Container() : nullptr;
257 if (!anchorNode || aCallerType == CallerType::System ||
258 !anchorNode->ChromeOnlyAccess()) {
259 return anchorNode;
261 // anchor is nsIContent as ChromeOnlyAccess is nsIContent-only
262 return anchorNode->AsContent()->FindFirstNonChromeOnlyAccessContent();
264 uint32_t AnchorOffset(CallerType aCallerType = CallerType::System) const {
265 const RangeBoundary& anchor = AnchorRef();
266 if (aCallerType != CallerType::System && anchor.IsSet() &&
267 anchor.Container()->ChromeOnlyAccess()) {
268 return 0;
270 const Maybe<uint32_t> offset =
271 anchor.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
272 return offset ? *offset : 0;
274 nsINode* GetFocusNode(CallerType aCallerType = CallerType::System) const {
275 const RangeBoundary& focus = FocusRef();
276 nsINode* focusNode = focus.IsSet() ? focus.Container() : nullptr;
277 if (!focusNode || aCallerType == CallerType::System ||
278 !focusNode->ChromeOnlyAccess()) {
279 return focusNode;
281 // focus is nsIContent as ChromeOnlyAccess is nsIContent-only
282 return focusNode->AsContent()->FindFirstNonChromeOnlyAccessContent();
284 uint32_t FocusOffset(CallerType aCallerType = CallerType::System) const {
285 const RangeBoundary& focus = FocusRef();
286 if (aCallerType != CallerType::System && focus.IsSet() &&
287 focus.Container()->ChromeOnlyAccess()) {
288 return 0;
290 const Maybe<uint32_t> offset =
291 focus.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
292 return offset ? *offset : 0;
295 nsIContent* GetChildAtAnchorOffset() {
296 const RangeBoundary& anchor = AnchorRef();
297 return anchor.IsSet() ? anchor.GetChildAtOffset() : nullptr;
299 nsIContent* GetChildAtFocusOffset() {
300 const RangeBoundary& focus = FocusRef();
301 return focus.IsSet() ? focus.GetChildAtOffset() : nullptr;
304 const RangeBoundary& AnchorRef() const;
305 const RangeBoundary& FocusRef() const;
308 * IsCollapsed -- is the whole selection just one point, or unset?
310 bool IsCollapsed() const {
311 uint32_t cnt = mStyledRanges.Length();
312 if (cnt == 0) {
313 return true;
316 if (cnt != 1) {
317 return false;
320 return mStyledRanges.mRanges[0].mRange->Collapsed();
323 // *JS() methods are mapped to Selection.*().
324 // They may move focus only when the range represents normal selection.
325 // These methods shouldn't be used by non-JS callers.
326 MOZ_CAN_RUN_SCRIPT void CollapseJS(nsINode* aContainer, uint32_t aOffset,
327 mozilla::ErrorResult& aRv);
328 MOZ_CAN_RUN_SCRIPT void CollapseToStartJS(mozilla::ErrorResult& aRv);
329 MOZ_CAN_RUN_SCRIPT void CollapseToEndJS(mozilla::ErrorResult& aRv);
331 MOZ_CAN_RUN_SCRIPT void ExtendJS(nsINode& aContainer, uint32_t aOffset,
332 mozilla::ErrorResult& aRv);
334 MOZ_CAN_RUN_SCRIPT void SelectAllChildrenJS(nsINode& aNode,
335 mozilla::ErrorResult& aRv);
338 * Deletes this selection from document the nodes belong to.
339 * Only if this has `SelectionType::eNormal`.
341 MOZ_CAN_RUN_SCRIPT void DeleteFromDocument(mozilla::ErrorResult& aRv);
343 uint32_t RangeCount() const { return mStyledRanges.Length(); }
345 void GetType(nsAString& aOutType) const;
347 nsRange* GetRangeAt(uint32_t aIndex, mozilla::ErrorResult& aRv);
348 MOZ_CAN_RUN_SCRIPT void AddRangeJS(nsRange& aRange,
349 mozilla::ErrorResult& aRv);
352 * Callers need to keep `aRange` alive.
354 MOZ_CAN_RUN_SCRIPT void RemoveRangeAndUnselectFramesAndNotifyListeners(
355 nsRange& aRange, mozilla::ErrorResult& aRv);
357 MOZ_CAN_RUN_SCRIPT void RemoveAllRanges(mozilla::ErrorResult& aRv);
360 * Whether Stringify should flush layout or not.
362 enum class FlushFrames { No, Yes };
363 MOZ_CAN_RUN_SCRIPT
364 void Stringify(nsAString& aResult, FlushFrames = FlushFrames::Yes);
367 * Indicates whether the node is part of the selection. If partlyContained
368 * is true, the function returns true when some part of the node
369 * is part of the selection. If partlyContained is false, the
370 * function only returns true when the entire node is part of the selection.
372 bool ContainsNode(nsINode& aNode, bool aPartlyContained,
373 mozilla::ErrorResult& aRv);
376 * Check to see if the given point is contained within the selection area. In
377 * particular, this iterates through all the rects that make up the selection,
378 * not just the bounding box, and checks to see if the given point is
379 * contained in any one of them.
380 * @param aPoint The point to check, relative to the root frame.
382 bool ContainsPoint(const nsPoint& aPoint);
385 * Modifies the selection. Note that the parameters are case-insensitive.
387 * @param alter can be one of { "move", "extend" }
388 * - "move" collapses the selection to the end of the selection and
389 * applies the movement direction/granularity to the collapsed
390 * selection.
391 * - "extend" leaves the start of the selection unchanged, and applies
392 * movement direction/granularity to the end of the selection.
393 * @param direction can be one of { "forward", "backward", "left", "right" }
394 * @param granularity can be one of { "character", "word",
395 * "line", "lineboundary" }
397 * @throws NS_ERROR_NOT_IMPLEMENTED if the granularity is "sentence",
398 * "sentenceboundary", "paragraph", "paragraphboundary", or
399 * "documentboundary". Throws NS_ERROR_INVALID_ARG if alter, direction,
400 * or granularity has an unrecognized value.
402 MOZ_CAN_RUN_SCRIPT void Modify(const nsAString& aAlter,
403 const nsAString& aDirection,
404 const nsAString& aGranularity,
405 mozilla::ErrorResult& aRv);
407 MOZ_CAN_RUN_SCRIPT
408 void SetBaseAndExtentJS(nsINode& aAnchorNode, uint32_t aAnchorOffset,
409 nsINode& aFocusNode, uint32_t aFocusOffset,
410 mozilla::ErrorResult& aRv);
412 bool GetInterlinePosition(mozilla::ErrorResult& aRv);
413 void SetInterlinePosition(bool aValue, mozilla::ErrorResult& aRv);
415 Nullable<int16_t> GetCaretBidiLevel(mozilla::ErrorResult& aRv) const;
416 void SetCaretBidiLevel(const Nullable<int16_t>& aCaretBidiLevel,
417 mozilla::ErrorResult& aRv);
419 void ToStringWithFormat(const nsAString& aFormatType, uint32_t aFlags,
420 int32_t aWrapColumn, nsAString& aReturn,
421 mozilla::ErrorResult& aRv);
422 void AddSelectionListener(nsISelectionListener* aListener);
423 void RemoveSelectionListener(nsISelectionListener* aListener);
425 RawSelectionType RawType() const {
426 return ToRawSelectionType(mSelectionType);
428 SelectionType Type() const { return mSelectionType; }
430 void GetRangesForInterval(nsINode& aBeginNode, int32_t aBeginOffset,
431 nsINode& aEndNode, int32_t aEndOffset,
432 bool aAllowAdjacent,
433 nsTArray<RefPtr<nsRange>>& aReturn,
434 mozilla::ErrorResult& aRv);
436 MOZ_CAN_RUN_SCRIPT void ScrollIntoView(int16_t aRegion, bool aIsSynchronous,
437 WhereToScroll aVPercent,
438 WhereToScroll aHPercent,
439 mozilla::ErrorResult& aRv);
441 void SetColors(const nsAString& aForeColor, const nsAString& aBackColor,
442 const nsAString& aAltForeColor, const nsAString& aAltBackColor,
443 mozilla::ErrorResult& aRv);
445 void ResetColors(mozilla::ErrorResult& aRv);
448 * Non-JS callers should use the following
449 * collapse/collapseToStart/extend/etc methods, instead of the *JS
450 * versions that bindings call.
454 * Collapses the selection to a single point, at the specified offset
455 * in the given node. When the selection is collapsed, and the content
456 * is focused and editable, the caret will blink there.
457 * @param aContainer The given node where the selection will be set
458 * @param offset Where in given dom node to place the selection (the
459 * offset into the given node)
461 MOZ_CAN_RUN_SCRIPT void CollapseInLimiter(nsINode& aContainer,
462 uint32_t aOffset,
463 ErrorResult& aRv) {
464 CollapseInternal(InLimiter::eYes, RawRangeBoundary(&aContainer, aOffset),
465 aRv);
468 private:
469 enum class InLimiter {
470 // If eYes, the method may reset selection limiter and move focus if the
471 // given range is out of the limiter.
472 eYes,
473 // If eNo, the method won't reset selection limiter. So, if given range
474 // is out of bounds, the method may return error.
475 eNo,
477 MOZ_CAN_RUN_SCRIPT
478 void CollapseInternal(InLimiter aInLimiter, const RawRangeBoundary& aPoint,
479 ErrorResult& aRv);
481 public:
483 * Collapses the whole selection to a single point at the start
484 * of the current selection (irrespective of direction). If content
485 * is focused and editable, the caret will blink there.
487 MOZ_CAN_RUN_SCRIPT void CollapseToStart(mozilla::ErrorResult& aRv);
490 * Collapses the whole selection to a single point at the end
491 * of the current selection (irrespective of direction). If content
492 * is focused and editable, the caret will blink there.
494 MOZ_CAN_RUN_SCRIPT void CollapseToEnd(mozilla::ErrorResult& aRv);
497 * Extends the selection by moving the selection end to the specified node and
498 * offset, preserving the selection begin position. The new selection end
499 * result will always be from the anchorNode to the new focusNode, regardless
500 * of direction.
502 * @param aContainer The node where the selection will be extended to
503 * @param aOffset Where in aContainer to place the offset of the new
504 * selection end.
506 MOZ_CAN_RUN_SCRIPT void Extend(nsINode& aContainer, uint32_t aOffset,
507 ErrorResult& aRv);
509 MOZ_CAN_RUN_SCRIPT void AddRangeAndSelectFramesAndNotifyListeners(
510 nsRange& aRange, mozilla::ErrorResult& aRv);
513 * Adds all children of the specified node to the selection.
514 * @param aNode the parent of the children to be added to the selection.
516 MOZ_CAN_RUN_SCRIPT void SelectAllChildren(nsINode& aNode,
517 mozilla::ErrorResult& aRv);
520 * SetStartAndEnd() removes all ranges and sets new range as given range.
521 * Different from SetBaseAndExtent(), this won't compare the DOM points of
522 * aStartRef and aEndRef for performance nor set direction to eDirPrevious.
523 * Note that this may reset the limiter and move focus. If you don't want
524 * that, use SetStartAndEndInLimiter() instead.
526 MOZ_CAN_RUN_SCRIPT
527 void SetStartAndEnd(const RawRangeBoundary& aStartRef,
528 const RawRangeBoundary& aEndRef, ErrorResult& aRv) {
529 SetStartAndEndInternal(InLimiter::eNo, aStartRef, aEndRef, eDirNext, aRv);
531 MOZ_CAN_RUN_SCRIPT
532 void SetStartAndEnd(nsINode& aStartContainer, uint32_t aStartOffset,
533 nsINode& aEndContainer, uint32_t aEndOffset,
534 ErrorResult& aRv) {
535 SetStartAndEnd(RawRangeBoundary(&aStartContainer, aStartOffset),
536 RawRangeBoundary(&aEndContainer, aEndOffset), aRv);
540 * SetStartAndEndInLimiter() is similar to SetStartAndEnd(), but this respects
541 * the selection limiter. If all or part of given range is not in the
542 * limiter, this returns error.
544 MOZ_CAN_RUN_SCRIPT
545 void SetStartAndEndInLimiter(const RawRangeBoundary& aStartRef,
546 const RawRangeBoundary& aEndRef,
547 ErrorResult& aRv) {
548 SetStartAndEndInternal(InLimiter::eYes, aStartRef, aEndRef, eDirNext, aRv);
550 MOZ_CAN_RUN_SCRIPT
551 void SetStartAndEndInLimiter(nsINode& aStartContainer, uint32_t aStartOffset,
552 nsINode& aEndContainer, uint32_t aEndOffset,
553 ErrorResult& aRv) {
554 SetStartAndEndInLimiter(RawRangeBoundary(&aStartContainer, aStartOffset),
555 RawRangeBoundary(&aEndContainer, aEndOffset), aRv);
559 * SetBaseAndExtent() is alternative of the JS API for internal use.
560 * Different from SetStartAndEnd(), this sets anchor and focus points as
561 * specified, then if anchor point is after focus node, this sets the
562 * direction to eDirPrevious.
563 * Note that this may reset the limiter and move focus. If you don't want
564 * that, use SetBaseAndExtentInLimier() instead.
566 MOZ_CAN_RUN_SCRIPT
567 void SetBaseAndExtent(nsINode& aAnchorNode, uint32_t aAnchorOffset,
568 nsINode& aFocusNode, uint32_t aFocusOffset,
569 ErrorResult& aRv);
570 MOZ_CAN_RUN_SCRIPT
571 void SetBaseAndExtent(const RawRangeBoundary& aAnchorRef,
572 const RawRangeBoundary& aFocusRef, ErrorResult& aRv) {
573 SetBaseAndExtentInternal(InLimiter::eNo, aAnchorRef, aFocusRef, aRv);
577 * SetBaseAndExtentInLimiter() is similar to SetBaseAndExtent(), but this
578 * respects the selection limiter. If all or part of given range is not in
579 * the limiter, this returns error.
581 MOZ_CAN_RUN_SCRIPT
582 void SetBaseAndExtentInLimiter(nsINode& aAnchorNode, uint32_t aAnchorOffset,
583 nsINode& aFocusNode, uint32_t aFocusOffset,
584 ErrorResult& aRv) {
585 SetBaseAndExtentInLimiter(RawRangeBoundary(&aAnchorNode, aAnchorOffset),
586 RawRangeBoundary(&aFocusNode, aFocusOffset), aRv);
588 MOZ_CAN_RUN_SCRIPT
589 void SetBaseAndExtentInLimiter(const RawRangeBoundary& aAnchorRef,
590 const RawRangeBoundary& aFocusRef,
591 ErrorResult& aRv) {
592 SetBaseAndExtentInternal(InLimiter::eYes, aAnchorRef, aFocusRef, aRv);
595 void AddSelectionChangeBlocker();
596 void RemoveSelectionChangeBlocker();
597 bool IsBlockingSelectionChangeEvents() const;
599 // Whether this selection is focused in an editable element.
600 bool IsEditorSelection() const;
603 * Set the painting style for the range. The range must be a range in
604 * the selection. The textRangeStyle will be used by text frame
605 * when it is painting the selection.
607 nsresult SetTextRangeStyle(nsRange* aRange,
608 const TextRangeStyle& aTextRangeStyle);
610 // Methods to manipulate our mFrameSelection's ancestor limiter.
611 nsIContent* GetAncestorLimiter() const;
612 void SetAncestorLimiter(nsIContent* aLimiter);
615 * Frame Offset cache can be used just during calling
616 * nsEditor::EndPlaceHolderTransaction. EndPlaceHolderTransaction will give
617 * rise to reflow/refreshing view/scroll, and call times of
618 * nsTextFrame::GetPointFromOffset whose return value is to be cached. see
619 * bugs 35296 and 199412
621 void SetCanCacheFrameOffset(bool aCanCacheFrameOffset);
623 // Selection::GetRangesForIntervalArray
625 // Fills a nsTArray with the ranges overlapping the range specified by
626 // the given endpoints. Ranges in the selection exactly adjacent to the
627 // input range are not returned unless aAllowAdjacent is set.
629 // For example, if the following ranges were in the selection
630 // (assume everything is within the same node)
632 // Start Offset: 0 2 7 9
633 // End Offset: 2 5 9 10
635 // and passed aBeginOffset of 2 and aEndOffset of 9, then with
636 // aAllowAdjacent set, all the ranges should be returned. If
637 // aAllowAdjacent was false, the ranges [2, 5] and [7, 9] only
638 // should be returned
640 // Now that overlapping ranges are disallowed, there can be a maximum of
641 // 2 adjacent ranges
642 nsresult GetRangesForIntervalArray(nsINode* aBeginNode, int32_t aBeginOffset,
643 nsINode* aEndNode, int32_t aEndOffset,
644 bool aAllowAdjacent,
645 nsTArray<nsRange*>* aRanges);
648 * Modifies the cursor Bidi level after a change in keyboard direction
649 * @param langRTL is true if the new language is right-to-left or
650 * false if the new language is left-to-right.
652 nsresult SelectionLanguageChange(bool aLangRTL);
654 private:
655 bool HasSameRootOrSameComposedDoc(const nsINode& aNode);
657 // XXX Please don't add additional uses of this method, it's only for
658 // XXX supporting broken code (bug 1245883) in the following classes:
659 friend class ::nsCopySupport;
660 friend class ::nsHTMLCopyEncoder;
661 MOZ_CAN_RUN_SCRIPT
662 void AddRangeAndSelectFramesAndNotifyListeners(nsRange& aRange,
663 Document* aDocument,
664 ErrorResult&);
666 // This is helper method for GetPrimaryFrameForFocusNode.
667 // If aVisual is true, this returns caret frame.
668 // If false, this returns primary frame.
669 nsIFrame* GetPrimaryOrCaretFrameForNodeOffset(nsIContent* aContent,
670 uint32_t aOffset,
671 int32_t* aOffsetUsed,
672 bool aVisual) const;
674 // Get the cached value for nsTextFrame::GetPointFromOffset.
675 nsresult GetCachedFrameOffset(nsIFrame* aFrame, int32_t inOffset,
676 nsPoint& aPoint);
678 MOZ_CAN_RUN_SCRIPT
679 void SetStartAndEndInternal(InLimiter aInLimiter,
680 const RawRangeBoundary& aStartRef,
681 const RawRangeBoundary& aEndRef,
682 nsDirection aDirection, ErrorResult& aRv);
683 MOZ_CAN_RUN_SCRIPT
684 void SetBaseAndExtentInternal(InLimiter aInLimiter,
685 const RawRangeBoundary& aAnchorRef,
686 const RawRangeBoundary& aFocusRef,
687 ErrorResult& aRv);
689 public:
690 SelectionType GetType() const { return mSelectionType; }
692 SelectionCustomColors* GetCustomColors() const { return mCustomColors.get(); }
694 MOZ_CAN_RUN_SCRIPT nsresult NotifySelectionListeners(bool aCalledByJS);
695 MOZ_CAN_RUN_SCRIPT nsresult NotifySelectionListeners();
697 friend struct AutoUserInitiated;
698 struct MOZ_RAII AutoUserInitiated {
699 explicit AutoUserInitiated(Selection* aSelection)
700 : mSavedValue(aSelection->mUserInitiated) {
701 aSelection->mUserInitiated = true;
703 AutoRestore<bool> mSavedValue;
706 private:
707 friend struct mozilla::AutoPrepareFocusRange;
708 class ScrollSelectionIntoViewEvent;
709 friend class ScrollSelectionIntoViewEvent;
711 class ScrollSelectionIntoViewEvent : public Runnable {
712 public:
713 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_DECL_NSIRUNNABLE
715 ScrollSelectionIntoViewEvent(Selection* aSelection, SelectionRegion aRegion,
716 ScrollAxis aVertical, ScrollAxis aHorizontal,
717 int32_t aFlags)
718 : Runnable("dom::Selection::ScrollSelectionIntoViewEvent"),
719 mSelection(aSelection),
720 mRegion(aRegion),
721 mVerticalScroll(aVertical),
722 mHorizontalScroll(aHorizontal),
723 mFlags(aFlags) {
724 NS_ASSERTION(aSelection, "null parameter");
726 void Revoke() { mSelection = nullptr; }
728 private:
729 Selection* mSelection;
730 SelectionRegion mRegion;
731 ScrollAxis mVerticalScroll;
732 ScrollAxis mHorizontalScroll;
733 int32_t mFlags;
737 * Set mAnchorFocusRange to mStyledRanges.mRanges[aIndex] if aIndex is a valid
738 * index. Set mAnchorFocusRange to nullptr if aIndex is negative. Otherwise,
739 * i.e., if aIndex is positive but out of bounds of mStyledRanges.mRanges, do
740 * nothing.
742 void SetAnchorFocusRange(int32_t aIndex);
743 void SelectFramesOf(nsIContent* aContent, bool aSelected) const;
746 * https://dom.spec.whatwg.org/#concept-tree-inclusive-descendant.
748 nsresult SelectFramesOfInclusiveDescendantsOfContent(
749 PostContentIterator& aPostOrderIter, nsIContent* aContent,
750 bool aSelected) const;
752 nsresult SelectFrames(nsPresContext* aPresContext, nsRange* aRange,
753 bool aSelect) const;
756 * SelectFramesInAllRanges() calls SelectFrames() for all current
757 * ranges.
759 void SelectFramesInAllRanges(nsPresContext* aPresContext);
762 * @param aOutIndex points to the index of the range in mStyledRanges.mRanges.
763 * If aDidAddRange is true, it is in [0, mStyledRanges.Length()).
765 MOZ_CAN_RUN_SCRIPT nsresult MaybeAddTableCellRange(nsRange& aRange,
766 bool* aDidAddRange,
767 int32_t* aOutIndex);
769 Document* GetDocument() const;
771 void Disconnect();
773 struct StyledRanges {
774 void Clear();
776 StyledRange* FindRangeData(nsRange* aRange);
778 using Elements = AutoTArray<StyledRange, 1>;
780 Elements::size_type Length() const;
782 nsresult RemoveCollapsedRanges();
784 nsresult RemoveRangeAndUnregisterSelection(nsRange& aRange);
787 * Binary searches the given sorted array of ranges for the insertion point
788 * for the given node/offset. The given comparator is used, and the index
789 * where the point should appear in the array is returned.
791 * If there is an item in the array equal to the input point (aPointNode,
792 * aPointOffset), we will return the index of this item.
794 * @return the index where the point should appear in the array. In
795 * [0, `aElementArray->Length()`].
797 static int32_t FindInsertionPoint(
798 const nsTArray<StyledRange>* aElementArray, const nsINode& aPointNode,
799 int32_t aPointOffset,
800 int32_t (*aComparator)(const nsINode&, int32_t, const nsRange&));
803 * Works on the same principle as GetRangesForIntervalArray, however
804 * instead this returns the indices into mRanges between which
805 * the overlapping ranges lie.
807 * @param aStartIndex will be less or equal than aEndIndex.
808 * @param aEndIndex can be in [-1, mRanges.Length()].
810 nsresult GetIndicesForInterval(const nsINode* aBeginNode,
811 int32_t aBeginOffset,
812 const nsINode* aEndNode, int32_t aEndOffset,
813 bool aAllowAdjacent, int32_t& aStartIndex,
814 int32_t& aEndIndex) const;
816 bool HasEqualRangeBoundariesAt(const nsRange& aRange,
817 int32_t aRangeIndex) const;
820 * Preserves the sorting and disjunctiveness of mRanges.
822 * @param aOutIndex will point to the index of the added range, or if aRange
823 * is already contained, to the one containing it. Hence
824 * it'll always be in [0, mRanges.Length()).
826 MOZ_CAN_RUN_SCRIPT nsresult MaybeAddRangeAndTruncateOverlaps(
827 nsRange* aRange, int32_t* aOutIndex, Selection& aSelection);
830 * GetCommonEditingHost() returns common editing host of all
831 * ranges if there is. If at least one of the ranges is in non-editable
832 * element, returns nullptr. See following examples for the detail:
834 * <div id="a" contenteditable>
835 * an[cestor
836 * <div id="b" contenteditable="false">
837 * non-editable
838 * <div id="c" contenteditable>
839 * desc]endant
840 * in this case, this returns div#a because div#c is also in div#a.
842 * <div id="a" contenteditable>
843 * an[ce]stor
844 * <div id="b" contenteditable="false">
845 * non-editable
846 * <div id="c" contenteditable>
847 * de[sc]endant
848 * in this case, this returns div#a because second range is also in div#a
849 * and common ancestor of the range (i.e., div#c) is editable.
851 * <div id="a" contenteditable>
852 * an[ce]stor
853 * <div id="b" contenteditable="false">
854 * [non]-editable
855 * <div id="c" contenteditable>
856 * de[sc]endant
857 * in this case, this returns nullptr because the second range is in
858 * non-editable area.
860 Element* GetCommonEditingHost() const;
862 MOZ_CAN_RUN_SCRIPT void MaybeFocusCommonEditingHost(
863 PresShell* aPresShell) const;
865 static nsresult SubtractRange(StyledRange& aRange, nsRange& aSubtract,
866 nsTArray<StyledRange>* aOutput);
868 void UnregisterSelection();
870 // These are the ranges inside this selection. They are kept sorted in order
871 // of DOM start position.
873 // This data structure is sorted by the range beginnings. As the ranges are
874 // disjoint, it is also implicitly sorted by the range endings. This allows
875 // us to perform binary searches when searching for existence of a range,
876 // giving us O(log n) search time.
878 // Inserting a new range requires finding the overlapping interval,
879 // requiring two binary searches plus up to an additional 6 DOM comparisons.
880 // If this proves to be a performance concern, then an interval tree may be
881 // a possible solution, allowing the calculation of the overlap interval in
882 // O(log n) time, though this would require rebalancing and other overhead.
883 Elements mRanges;
886 StyledRanges mStyledRanges;
888 RefPtr<nsRange> mAnchorFocusRange;
889 RefPtr<nsFrameSelection> mFrameSelection;
890 RefPtr<AccessibleCaretEventHub> mAccessibleCaretEventHub;
891 RefPtr<SelectionChangeEventDispatcher> mSelectionChangeEventDispatcher;
892 RefPtr<AutoScroller> mAutoScroller;
893 nsTArray<nsCOMPtr<nsISelectionListener>> mSelectionListeners;
894 nsRevocableEventPtr<ScrollSelectionIntoViewEvent> mScrollEvent;
895 CachedOffsetForFrame* mCachedOffsetForFrame;
896 nsDirection mDirection;
897 const SelectionType mSelectionType;
898 UniquePtr<SelectionCustomColors> mCustomColors;
900 // Non-zero if we don't want any changes we make to the selection to be
901 // visible to content. If non-zero, content won't be notified about changes.
902 uint32_t mSelectionChangeBlockerCount;
905 * True if the current selection operation was initiated by user action.
906 * It determines whether we exclude -moz-user-select:none nodes or not,
907 * as well as whether selectstart events will be fired.
909 bool mUserInitiated;
912 * When the selection change is caused by a call of Selection API,
913 * mCalledByJS is true. Otherwise, false.
915 bool mCalledByJS;
918 * true if AutoCopyListner::OnSelectionChange() should be called.
920 bool mNotifyAutoCopy;
923 // Stack-class to turn on/off selection batching.
924 class MOZ_STACK_CLASS SelectionBatcher final {
925 private:
926 RefPtr<Selection> mSelection;
928 public:
929 explicit SelectionBatcher(Selection* aSelection) {
930 mSelection = aSelection;
931 if (mSelection) {
932 mSelection->StartBatchChanges();
936 ~SelectionBatcher() {
937 if (mSelection) {
938 mSelection->EndBatchChanges();
943 class MOZ_RAII AutoHideSelectionChanges final {
944 private:
945 RefPtr<Selection> mSelection;
947 public:
948 explicit AutoHideSelectionChanges(const nsFrameSelection* aFrame);
950 explicit AutoHideSelectionChanges(Selection* aSelection)
951 : mSelection(aSelection) {
952 mSelection = aSelection;
953 if (mSelection) {
954 mSelection->AddSelectionChangeBlocker();
958 ~AutoHideSelectionChanges() {
959 if (mSelection) {
960 mSelection->RemoveSelectionChangeBlocker();
965 } // namespace dom
967 inline bool IsValidRawSelectionType(RawSelectionType aRawSelectionType) {
968 return aRawSelectionType >= nsISelectionController::SELECTION_NONE &&
969 aRawSelectionType <= nsISelectionController::SELECTION_URLSTRIKEOUT;
972 inline SelectionType ToSelectionType(RawSelectionType aRawSelectionType) {
973 if (!IsValidRawSelectionType(aRawSelectionType)) {
974 return SelectionType::eInvalid;
976 return static_cast<SelectionType>(aRawSelectionType);
979 inline RawSelectionType ToRawSelectionType(SelectionType aSelectionType) {
980 MOZ_ASSERT(aSelectionType != SelectionType::eInvalid);
981 return static_cast<RawSelectionType>(aSelectionType);
984 inline RawSelectionType ToRawSelectionType(TextRangeType aTextRangeType) {
985 return ToRawSelectionType(ToSelectionType(aTextRangeType));
988 inline SelectionTypeMask ToSelectionTypeMask(SelectionType aSelectionType) {
989 MOZ_ASSERT(aSelectionType != SelectionType::eInvalid);
990 return aSelectionType == SelectionType::eNone
992 : static_cast<SelectionTypeMask>(
993 1 << (static_cast<uint8_t>(aSelectionType) - 1));
996 } // namespace mozilla
998 #endif // mozilla_Selection_h__