Backed out changeset 9d8b4c0b99ed (bug 1945683) for causing btime failures. CLOSED...
[gecko.git] / dom / base / nsRange.h
blob6ee0f4c2012128086aa2455c9fa5685a088c68f5
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * Implementation of the DOM Range object.
9 */
11 #ifndef nsRange_h___
12 #define nsRange_h___
14 #include "nsCOMPtr.h"
15 #include "mozilla/dom/AbstractRange.h"
16 #include "mozilla/dom/StaticRange.h"
17 #include "mozilla/dom/CrossShadowBoundaryRange.h"
18 #include "prmon.h"
19 #include "nsStubMutationObserver.h"
20 #include "nsWrapperCache.h"
21 #include "mozilla/Attributes.h"
22 #include "mozilla/ErrorResult.h"
23 #include "mozilla/RangeBoundary.h"
24 #include "mozilla/RefPtr.h"
26 namespace mozilla {
27 class RectCallback;
28 namespace dom {
29 struct ClientRectsAndTexts;
30 class DocGroup;
31 class DocumentFragment;
32 class DOMRect;
33 class DOMRectList;
34 class InspectorFontFace;
35 class Selection;
36 class TrustedHTMLOrString;
38 enum class RangeBehaviour : uint8_t {
39 // Keep both ranges
40 KeepDefaultRangeAndCrossShadowBoundaryRanges,
41 // Merge both ranges; This is the case where the range boundaries was in
42 // different roots initially, and becoming in the same roots now. Since
43 // they start to be in the same root, using normal range is good enough
44 // to represent it
45 MergeDefaultRangeAndCrossShadowBoundaryRanges,
46 // Collapse the default range
47 CollapseDefaultRange,
48 // Collapse both the default range and the cross-shadow-boundary range
49 CollapseDefaultRangeAndCrossShadowBoundaryRanges
52 } // namespace dom
53 } // namespace mozilla
55 class nsRange final : public mozilla::dom::AbstractRange,
56 public nsStubMutationObserver {
57 using ErrorResult = mozilla::ErrorResult;
58 using AbstractRange = mozilla::dom::AbstractRange;
59 using DocGroup = mozilla::dom::DocGroup;
60 using DOMRect = mozilla::dom::DOMRect;
61 using DOMRectList = mozilla::dom::DOMRectList;
62 using RangeBoundary = mozilla::RangeBoundary;
63 using RawRangeBoundary = mozilla::RawRangeBoundary;
64 using AllowRangeCrossShadowBoundary =
65 mozilla::dom::AllowRangeCrossShadowBoundary;
67 virtual ~nsRange();
68 explicit nsRange(nsINode* aNode);
70 public:
71 /**
72 * The following Create() returns `nsRange` instance which is initialized
73 * only with aNode. The result is never positioned.
75 static already_AddRefed<nsRange> Create(nsINode* aNode);
77 /**
78 * The following Create() may return `nsRange` instance which is initialized
79 * with given range or points. If it fails initializing new range with the
80 * arguments, returns `nullptr`. `ErrorResult` is set to an error only
81 * when this returns `nullptr`. The error code indicates the reason why
82 * it couldn't initialize the instance.
84 static already_AddRefed<nsRange> Create(const AbstractRange* aAbstractRange,
85 ErrorResult& aRv) {
86 return nsRange::Create(aAbstractRange->StartRef(), aAbstractRange->EndRef(),
87 aRv);
89 static already_AddRefed<nsRange> Create(nsINode* aStartContainer,
90 uint32_t aStartOffset,
91 nsINode* aEndContainer,
92 uint32_t aEndOffset,
93 ErrorResult& aRv) {
94 return nsRange::Create(RawRangeBoundary(aStartContainer, aStartOffset),
95 RawRangeBoundary(aEndContainer, aEndOffset), aRv);
97 template <typename SPT, typename SRT, typename EPT, typename ERT>
98 static already_AddRefed<nsRange> Create(
99 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
100 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary,
101 ErrorResult& aRv);
103 NS_DECL_ISUPPORTS_INHERITED
104 NS_IMETHODIMP_(void) DeleteCycleCollectable(void) override;
105 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsRange, AbstractRange)
107 nsrefcnt GetRefCount() const { return mRefCnt; }
109 nsINode* GetRoot() const { return mRoot; }
112 * Return true if this range was generated.
113 * @see SetIsGenerated
115 bool IsGenerated() const { return mIsGenerated; }
118 * Mark this range as being generated or not.
119 * Currently it is used for marking ranges that are created when splitting up
120 * a range to exclude a -moz-user-select:none region.
121 * @see Selection::AddRangesForSelectableNodes
122 * @see ExcludeNonSelectableNodes
124 void SetIsGenerated(bool aIsGenerated) { mIsGenerated = aIsGenerated; }
126 void Reset();
129 * SetStart() and SetEnd() sets start point or end point separately.
130 * However, this is expensive especially when it's a range of Selection.
131 * When you set both start and end of a range, you should use
132 * SetStartAndEnd() instead.
134 nsresult SetStart(nsINode* aContainer, uint32_t aOffset,
135 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
136 AllowRangeCrossShadowBoundary::No) {
137 ErrorResult error;
138 SetStart(RawRangeBoundary(aContainer, aOffset), error,
139 aAllowCrossShadowBoundary);
140 return error.StealNSResult();
142 nsresult SetEnd(nsINode* aContainer, uint32_t aOffset,
143 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
144 AllowRangeCrossShadowBoundary::No) {
145 ErrorResult error;
146 SetEnd(RawRangeBoundary(aContainer, aOffset), error,
147 aAllowCrossShadowBoundary);
148 return error.StealNSResult();
151 already_AddRefed<nsRange> CloneRange() const;
154 * SetStartAndEnd() works similar to call both SetStart() and SetEnd().
155 * Different from calls them separately, this does nothing if either
156 * the start point or the end point is invalid point.
157 * If the specified start point is after the end point, the range will be
158 * collapsed at the end point. Similarly, if they are in different root,
159 * the range will be collapsed at the end point.
161 nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
162 nsINode* aEndContainer, uint32_t aEndOffset) {
163 return SetStartAndEnd(RawRangeBoundary(aStartContainer, aStartOffset),
164 RawRangeBoundary(aEndContainer, aEndOffset));
166 template <typename SPT, typename SRT, typename EPT, typename ERT>
167 nsresult SetStartAndEnd(
168 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
169 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary) {
170 return AbstractRange::SetStartAndEndInternal(aStartBoundary, aEndBoundary,
171 this);
175 * Adds all nodes between |aStartContent| and |aEndContent| to the range.
176 * The start offset will be set before |aStartContent|,
177 * while the end offset will be set immediately after |aEndContent|.
179 * Caller must guarantee both nodes are non null and
180 * children of |aContainer| and that |aEndContent| is after |aStartContent|.
182 void SelectNodesInContainer(nsINode* aContainer, nsIContent* aStartContent,
183 nsIContent* aEndContent);
186 * CollapseTo() works similar to call both SetStart() and SetEnd() with
187 * same node and offset. This just calls SetStartAndParent() to set
188 * collapsed range at aContainer and aOffset.
190 nsresult CollapseTo(nsINode* aContainer, uint32_t aOffset) {
191 return CollapseTo(RawRangeBoundary(aContainer, aOffset));
193 nsresult CollapseTo(const RawRangeBoundary& aPoint) {
194 return SetStartAndEnd(aPoint, aPoint);
197 // aMaxRanges is the maximum number of text ranges to record for each face
198 // (pass 0 to just get the list of faces, without recording exact ranges
199 // where each face was used).
200 nsresult GetUsedFontFaces(
201 nsTArray<mozilla::UniquePtr<mozilla::dom::InspectorFontFace>>& aResult,
202 uint32_t aMaxRanges, bool aSkipCollapsedWhitespace);
204 // nsIMutationObserver methods
205 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
206 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
207 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
208 NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
209 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
211 // WebIDL
212 static already_AddRefed<nsRange> Constructor(
213 const mozilla::dom::GlobalObject& global, mozilla::ErrorResult& aRv);
215 already_AddRefed<mozilla::dom::DocumentFragment> CreateContextualFragment(
216 const nsAString& aString, ErrorResult& aError) const;
217 MOZ_CAN_RUN_SCRIPT already_AddRefed<mozilla::dom::DocumentFragment>
218 CreateContextualFragment(const mozilla::dom::TrustedHTMLOrString&,
219 ErrorResult& aError) const;
220 already_AddRefed<mozilla::dom::DocumentFragment> CloneContents(
221 ErrorResult& aErr);
222 int16_t CompareBoundaryPoints(uint16_t aHow, const nsRange& aOtherRange,
223 ErrorResult& aRv);
224 int16_t ComparePoint(const nsINode& aContainer, uint32_t aOffset,
225 ErrorResult& aRv,
226 bool aAllowCrossShadowBoundary = false) const;
227 void DeleteContents(ErrorResult& aRv);
228 already_AddRefed<mozilla::dom::DocumentFragment> ExtractContents(
229 ErrorResult& aErr);
230 nsINode* GetCommonAncestorContainer(
231 ErrorResult& aRv,
232 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
233 AllowRangeCrossShadowBoundary::No) const {
234 if (!mIsPositioned) {
235 aRv.Throw(NS_ERROR_NOT_INITIALIZED);
236 return nullptr;
238 return GetClosestCommonInclusiveAncestor(aAllowCrossShadowBoundary);
240 void InsertNode(nsINode& aNode, ErrorResult& aErr);
241 bool IntersectsNode(nsINode& aNode, ErrorResult& aRv);
242 bool IsPointInRange(const nsINode& aContainer, uint32_t aOffset,
243 ErrorResult& aRv,
244 bool aAllowCrossShadowBoundary = false) const;
245 void ToString(nsAString& aReturn, ErrorResult& aErr);
246 void Detach();
248 // *JS() methods are mapped to Range.*() of DOM.
249 // They may move focus only when the range represents normal selection.
250 // These methods shouldn't be used from internal.
251 void CollapseJS(bool aToStart);
252 void SelectNodeJS(nsINode& aNode, ErrorResult& aErr);
253 void SelectNodeContentsJS(nsINode& aNode, ErrorResult& aErr);
254 void SetEndJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
255 void SetEndAfterJS(nsINode& aNode, ErrorResult& aErr);
256 void SetEndBeforeJS(nsINode& aNode, ErrorResult& aErr);
257 void SetStartJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
258 void SetStartAfterJS(nsINode& aNode, ErrorResult& aErr);
259 void SetStartBeforeJS(nsINode& aNode, ErrorResult& aErr);
261 void SetStartAllowCrossShadowBoundary(nsINode& aNode, uint32_t aOffset,
262 ErrorResult& aErr);
263 void SetEndAllowCrossShadowBoundary(nsINode& aNode, uint32_t aOffset,
264 ErrorResult& aErr);
266 void SurroundContents(nsINode& aNode, ErrorResult& aErr);
267 already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true,
268 bool aFlushLayout = true);
269 already_AddRefed<DOMRectList> GetClientRects(bool aClampToEdge = true,
270 bool aFlushLayout = true);
271 // ChromeOnly
272 already_AddRefed<DOMRectList> GetAllowCrossShadowBoundaryClientRects(
273 bool aClampToEdge = true, bool aFlushLayout = true);
275 void GetClientRectsAndTexts(mozilla::dom::ClientRectsAndTexts& aResult,
276 ErrorResult& aErr);
278 // Following methods should be used for internal use instead of *JS().
279 void SelectNode(nsINode& aNode, ErrorResult& aErr);
280 void SelectNodeContents(nsINode& aNode, ErrorResult& aErr);
281 void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr,
282 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
283 AllowRangeCrossShadowBoundary::No);
284 void SetEnd(const RawRangeBoundary& aPoint, ErrorResult& aErr,
285 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
286 AllowRangeCrossShadowBoundary::No);
287 void SetEndAfter(nsINode& aNode, ErrorResult& aErr);
288 void SetEndBefore(nsINode& aNode, ErrorResult& aErr,
289 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
290 AllowRangeCrossShadowBoundary::No);
291 void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr,
292 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
293 AllowRangeCrossShadowBoundary::No);
294 void SetStart(const RawRangeBoundary& aPoint, ErrorResult& aErr,
295 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
296 AllowRangeCrossShadowBoundary::No);
297 void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
298 void SetStartBefore(nsINode& aNode, ErrorResult& aErr,
299 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
300 AllowRangeCrossShadowBoundary::No);
301 void Collapse(bool aToStart);
303 static void GetInnerTextNoFlush(mozilla::dom::DOMString& aValue,
304 mozilla::ErrorResult& aError,
305 nsIContent* aContainer);
307 virtual JSObject* WrapObject(JSContext* cx,
308 JS::Handle<JSObject*> aGivenProto) final;
309 DocGroup* GetDocGroup() const;
311 // Given a CharacterDataChangeInfo and an RangeBoundary of where the
312 // character changes occurred at, compute the new boundary.
313 static RawRangeBoundary ComputeNewBoundaryWhenBoundaryInsideChangedText(
314 const CharacterDataChangeInfo& aInfo, const RawRangeBoundary& aBoundary);
316 private:
317 // no copy's or assigns
318 nsRange(const nsRange&);
319 nsRange& operator=(const nsRange&);
321 template <typename SPT, typename SRT, typename EPT, typename ERT>
322 static void AssertIfMismatchRootAndRangeBoundaries(
323 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
324 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary,
325 const nsINode* aRootNode, bool aNotInsertedYet = false);
328 * Cut or delete the range's contents.
330 * @param aFragment DocumentFragment containing the nodes.
331 * May be null to indicate the caller doesn't want a
332 * fragment.
333 * @param aRv The error if any.
335 void CutContents(mozilla::dom::DocumentFragment** aFragment,
336 ErrorResult& aRv);
338 static nsresult CloneParentsBetween(nsINode* aAncestor, nsINode* aNode,
339 nsINode** aClosestAncestor,
340 nsINode** aFarthestAncestor);
343 * Returns whether a node is safe to be accessed by the current caller.
345 bool CanAccess(const nsINode&) const;
347 void AdjustNextRefsOnCharacterDataSplit(const nsIContent& aContent,
348 const CharacterDataChangeInfo& aInfo);
350 struct RangeBoundariesAndRoot {
351 RawRangeBoundary mStart;
352 RawRangeBoundary mEnd;
353 nsINode* mRoot = nullptr;
357 * @param aContent Must be non-nullptr.
359 RangeBoundariesAndRoot DetermineNewRangeBoundariesAndRootOnCharacterDataMerge(
360 nsIContent* aContent, const CharacterDataChangeInfo& aInfo) const;
362 // @return true iff the range is positioned, aContainer belongs to the same
363 // document as the range, aContainer is a DOCUMENT_TYPE_NODE and
364 // aOffset doesn't exceed aContainer's length.
365 bool IsPointComparableToRange(const nsINode& aContainer, uint32_t aOffset,
366 bool aAllowCrossShadowBoundary,
367 ErrorResult& aErrorResult) const;
369 // @return true iff aContainer is a shadow including inclusive descendant of
370 // the common ancestor of the mCrossBoundaryRange.
371 bool IsShadowIncludingInclusiveDescendantOfCrossBoundaryRangeAncestor(
372 const nsINode& aContainer) const;
375 * @brief Returns true if the range is part of exactly one |Selection|.
377 bool IsPartOfOneSelectionOnly() const { return mSelections.Length() == 1; };
379 already_AddRefed<DOMRectList> GetClientRectsInner(
380 AllowRangeCrossShadowBoundary = AllowRangeCrossShadowBoundary::No,
381 bool aClampToEdge = true, bool aFlushLayout = true);
383 public:
385 * This helper function gets rects and correlated text for the given range.
386 * @param aTextList optional where nullptr = don't retrieve text
388 static void CollectClientRectsAndText(
389 mozilla::RectCallback* aCollector,
390 mozilla::dom::Sequence<nsString>* aTextList, nsRange* aRange,
391 nsINode* aStartContainer, uint32_t aStartOffset, nsINode* aEndContainer,
392 uint32_t aEndOffset, bool aClampToEdge, bool aFlushLayout);
395 * Scan this range for -moz-user-select:none nodes and split it up into
396 * multiple ranges to exclude those nodes. The resulting ranges are put
397 * in aOutRanges. If no -moz-user-select:none node is found in the range
398 * then |this| is unmodified and is the only range in aOutRanges.
399 * Otherwise, |this| will be modified so that it ends before the first
400 * -moz-user-select:none node and additional ranges may also be created.
401 * If all nodes in the range are -moz-user-select:none then aOutRanges
402 * will be empty.
403 * @param aOutRanges the resulting set of ranges
405 void ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges);
408 * Notify the selection listeners after a range has been modified.
410 MOZ_CAN_RUN_SCRIPT void NotifySelectionListenersAfterRangeSet();
413 * For a range for which IsInSelection() is true, return the closest common
414 * inclusive ancestor
415 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor)
416 * for the range, which we had to compute when the common ancestor changed or
417 * IsInSelection became true, so we could register with it. That is, it's a
418 * faster version of GetClosestCommonInclusiveAncestor that only works for
419 * ranges in a Selection. The method will assert and the behavior is undefined
420 * if called on a range where IsInSelection() is false.
422 nsINode* GetRegisteredClosestCommonInclusiveAncestor();
424 template <typename SPT, typename SRT, typename EPT, typename ERT>
425 void CreateOrUpdateCrossShadowBoundaryRangeIfNeeded(
426 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
427 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary);
429 void ResetCrossShadowBoundaryRange() { mCrossShadowBoundaryRange = nullptr; }
431 #ifdef DEBUG
432 bool CrossShadowBoundaryRangeCollapsed() const {
433 MOZ_ASSERT(mCrossShadowBoundaryRange);
435 return !mCrossShadowBoundaryRange->IsPositioned() ||
436 (mCrossShadowBoundaryRange->GetStartContainer() ==
437 mCrossShadowBoundaryRange->GetEndContainer() &&
438 mCrossShadowBoundaryRange->StartOffset() ==
439 mCrossShadowBoundaryRange->EndOffset());
441 #endif
444 * The methods marked with MayCrossShadowBoundary[..] additionally check for
445 * the existence of mCrossShadowBoundaryRange, which indicates a range that
446 * crosses a shadow DOM boundary (i.e. mStart and mEnd are in different
447 * trees). If the caller can guarantee that this does not happen, there are
448 * additional variants of these methods named without MayCrossShadowBoundary,
449 * which provide a slightly faster implementation.
450 * */
452 nsIContent* GetMayCrossShadowBoundaryChildAtStartOffset() const {
453 return mCrossShadowBoundaryRange
454 ? mCrossShadowBoundaryRange->GetChildAtStartOffset()
455 : mStart.GetChildAtOffset();
458 nsIContent* GetMayCrossShadowBoundaryChildAtEndOffset() const {
459 return mCrossShadowBoundaryRange
460 ? mCrossShadowBoundaryRange->GetChildAtEndOffset()
461 : mEnd.GetChildAtOffset();
464 mozilla::dom::CrossShadowBoundaryRange* GetCrossShadowBoundaryRange() const {
465 return mCrossShadowBoundaryRange;
468 nsINode* GetMayCrossShadowBoundaryStartContainer() const {
469 return mCrossShadowBoundaryRange
470 ? mCrossShadowBoundaryRange->GetStartContainer()
471 : mStart.Container();
474 nsINode* GetMayCrossShadowBoundaryEndContainer() const {
475 return mCrossShadowBoundaryRange
476 ? mCrossShadowBoundaryRange->GetEndContainer()
477 : mEnd.Container();
480 uint32_t MayCrossShadowBoundaryStartOffset() const {
481 return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->StartOffset()
482 : StartOffset();
485 uint32_t MayCrossShadowBoundaryEndOffset() const {
486 return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->EndOffset()
487 : EndOffset();
490 const RangeBoundary& MayCrossShadowBoundaryStartRef() const {
491 return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->StartRef()
492 : StartRef();
495 const RangeBoundary& MayCrossShadowBoundaryEndRef() const {
496 return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->EndRef()
497 : EndRef();
500 protected:
502 * DoSetRange() is called when `AbstractRange::SetStartAndEndInternal()` sets
503 * mStart and mEnd, or some other internal methods modify `mStart` and/or
504 * `mEnd`. Therefore, this shouldn't be a virtual method.
506 * @param aStartBoundary Computed start point. This must equals or be
507 * before aEndBoundary in the DOM tree order.
508 * @param aEndBoundary Computed end point.
509 * @param aRootNode The root node.
510 * @param aNotInsertedYet true if this is called by CharacterDataChanged()
511 * to disable assertion and suppress re-registering
512 * a range common ancestor node since the new text
513 * node of a splitText hasn't been inserted yet.
514 * CharacterDataChanged() does the re-registering
515 * when needed. Otherwise, false.
517 template <typename SPT, typename SRT, typename EPT, typename ERT>
518 MOZ_CAN_RUN_SCRIPT_BOUNDARY void DoSetRange(
519 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
520 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary,
521 nsINode* aRootNode, bool aNotInsertedYet = false,
522 mozilla::dom::RangeBehaviour aRangeBehaviour = mozilla::dom::
523 RangeBehaviour::CollapseDefaultRangeAndCrossShadowBoundaryRanges);
525 // Assume that this is guaranteed that this is held by the caller when
526 // this is used. (Note that we cannot use AutoRestore for mCalledByJS
527 // due to a bit field.)
528 class MOZ_RAII AutoCalledByJSRestore final {
529 private:
530 nsRange& mRange;
531 bool mOldValue;
533 public:
534 explicit AutoCalledByJSRestore(nsRange& aRange)
535 : mRange(aRange), mOldValue(aRange.mCalledByJS) {}
536 ~AutoCalledByJSRestore() { mRange.mCalledByJS = mOldValue; }
537 bool SavedValue() const { return mOldValue; }
540 struct MOZ_STACK_CLASS AutoInvalidateSelection {
541 explicit AutoInvalidateSelection(nsRange* aRange) : mRange(aRange) {
542 if (!mRange->IsInAnySelection() || sIsNested) {
543 return;
545 sIsNested = true;
546 mCommonAncestor = mRange->GetRegisteredClosestCommonInclusiveAncestor();
548 ~AutoInvalidateSelection();
549 nsRange* mRange;
550 RefPtr<nsINode> mCommonAncestor;
551 static bool sIsNested;
554 bool MaybeInterruptLastRelease();
556 #ifdef DEBUG
557 bool IsCleared() const {
558 return !mRoot && !mRegisteredClosestCommonInclusiveAncestor &&
559 mSelections.IsEmpty() && !mNextStartRef && !mNextEndRef;
561 #endif // #ifdef DEBUG
563 nsCOMPtr<nsINode> mRoot;
565 // These raw pointers are used to remember a child that is about
566 // to be inserted between a CharacterData call and a subsequent
567 // ContentInserted or ContentAppended call. It is safe to store
568 // these refs because the caller is guaranteed to trigger both
569 // notifications while holding a strong reference to the new child.
570 nsIContent* MOZ_NON_OWNING_REF mNextStartRef;
571 nsIContent* MOZ_NON_OWNING_REF mNextEndRef;
573 static nsTArray<RefPtr<nsRange>>* sCachedRanges;
575 // Used to keep track of the real start and end for a
576 // selection where the start and the end are in different trees.
577 // It's NULL when the nodes are in the same tree.
579 // mCrossShadowBoundaryRange doesn't deal with DOM mutations, because
580 // it's still an open question about how it should be handled.
581 // Spec: https://github.com/w3c/selection-api/issues/168.
582 // As a result, it'll be set to NULL if that happens.
584 // Theoretically, mCrossShadowBoundaryRange isn't really needed because
585 // we should be able to always store the real start and end, and
586 // just return one point when a collapse is needed.
587 // Bug https://bugzilla.mozilla.org/show_bug.cgi?id=1886028 is going
588 // to be used to improve mCrossShadowBoundaryRange.
589 RefPtr<mozilla::dom::CrossShadowBoundaryRange> mCrossShadowBoundaryRange;
591 friend class mozilla::dom::AbstractRange;
593 namespace mozilla::dom {
594 inline nsRange* AbstractRange::AsDynamicRange() {
595 MOZ_ASSERT(IsDynamicRange());
596 return static_cast<nsRange*>(this);
598 inline const nsRange* AbstractRange::AsDynamicRange() const {
599 MOZ_ASSERT(IsDynamicRange());
600 return static_cast<const nsRange*>(this);
602 } // namespace mozilla::dom
603 #endif /* nsRange_h___ */