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/. */
8 * Implementation of the DOM Range object.
15 #include "mozilla/dom/AbstractRange.h"
16 #include "mozilla/dom/StaticRange.h"
17 #include "mozilla/dom/CrossShadowBoundaryRange.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"
29 struct ClientRectsAndTexts
;
31 class DocumentFragment
;
34 class InspectorFontFace
;
36 class TrustedHTMLOrString
;
38 enum class RangeBehaviour
: uint8_t {
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
45 MergeDefaultRangeAndCrossShadowBoundaryRanges
,
46 // Collapse the default range
48 // Collapse both the default range and the cross-shadow-boundary range
49 CollapseDefaultRangeAndCrossShadowBoundaryRanges
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
;
68 explicit nsRange(nsINode
* aNode
);
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
);
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
,
86 return nsRange::Create(aAbstractRange
->StartRef(), aAbstractRange
->EndRef(),
89 static already_AddRefed
<nsRange
> Create(nsINode
* aStartContainer
,
90 uint32_t aStartOffset
,
91 nsINode
* aEndContainer
,
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
,
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
; }
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
) {
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
) {
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
,
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
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(
222 int16_t CompareBoundaryPoints(uint16_t aHow
, const nsRange
& aOtherRange
,
224 int16_t ComparePoint(const nsINode
& aContainer
, uint32_t aOffset
,
226 bool aAllowCrossShadowBoundary
= false) const;
227 void DeleteContents(ErrorResult
& aRv
);
228 already_AddRefed
<mozilla::dom::DocumentFragment
> ExtractContents(
230 nsINode
* GetCommonAncestorContainer(
232 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary
=
233 AllowRangeCrossShadowBoundary::No
) const {
234 if (!mIsPositioned
) {
235 aRv
.Throw(NS_ERROR_NOT_INITIALIZED
);
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
,
244 bool aAllowCrossShadowBoundary
= false) const;
245 void ToString(nsAString
& aReturn
, ErrorResult
& aErr
);
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
,
263 void SetEndAllowCrossShadowBoundary(nsINode
& aNode
, uint32_t aOffset
,
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);
272 already_AddRefed
<DOMRectList
> GetAllowCrossShadowBoundaryClientRects(
273 bool aClampToEdge
= true, bool aFlushLayout
= true);
275 void GetClientRectsAndTexts(mozilla::dom::ClientRectsAndTexts
& aResult
,
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
);
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
333 * @param aRv The error if any.
335 void CutContents(mozilla::dom::DocumentFragment
** aFragment
,
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);
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
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
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; }
432 bool CrossShadowBoundaryRangeCollapsed() const {
433 MOZ_ASSERT(mCrossShadowBoundaryRange
);
435 return !mCrossShadowBoundaryRange
->IsPositioned() ||
436 (mCrossShadowBoundaryRange
->GetStartContainer() ==
437 mCrossShadowBoundaryRange
->GetEndContainer() &&
438 mCrossShadowBoundaryRange
->StartOffset() ==
439 mCrossShadowBoundaryRange
->EndOffset());
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.
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()
480 uint32_t MayCrossShadowBoundaryStartOffset() const {
481 return mCrossShadowBoundaryRange
? mCrossShadowBoundaryRange
->StartOffset()
485 uint32_t MayCrossShadowBoundaryEndOffset() const {
486 return mCrossShadowBoundaryRange
? mCrossShadowBoundaryRange
->EndOffset()
490 const RangeBoundary
& MayCrossShadowBoundaryStartRef() const {
491 return mCrossShadowBoundaryRange
? mCrossShadowBoundaryRange
->StartRef()
495 const RangeBoundary
& MayCrossShadowBoundaryEndRef() const {
496 return mCrossShadowBoundaryRange
? mCrossShadowBoundaryRange
->EndRef()
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
{
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
) {
546 mCommonAncestor
= mRange
->GetRegisteredClosestCommonInclusiveAncestor();
548 ~AutoInvalidateSelection();
550 RefPtr
<nsINode
> mCommonAncestor
;
551 static bool sIsNested
;
554 bool MaybeInterruptLastRelease();
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___ */