Backed out changeset 1d9301697aa0 (bug 1887752) for causing failures on browser_all_f...
[gecko.git] / dom / base / nsRange.h
blob3c8f43a7dc3ff171eb1050574f428183c59a2fd8
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;
37 enum class CollapsePolicy : uint8_t {
38 No, // Don't need to collapse
39 DefaultRange, // Collapse the default range
40 DefaultRangeAndCrossShadowBoundaryRanges // Collapse both the default range
41 // and the cross boundary range
43 } // namespace dom
44 } // namespace mozilla
46 class nsRange final : public mozilla::dom::AbstractRange,
47 public nsStubMutationObserver {
48 using ErrorResult = mozilla::ErrorResult;
49 using AbstractRange = mozilla::dom::AbstractRange;
50 using DocGroup = mozilla::dom::DocGroup;
51 using DOMRect = mozilla::dom::DOMRect;
52 using DOMRectList = mozilla::dom::DOMRectList;
53 using RangeBoundary = mozilla::RangeBoundary;
54 using RawRangeBoundary = mozilla::RawRangeBoundary;
55 using AllowRangeCrossShadowBoundary =
56 mozilla::dom::AllowRangeCrossShadowBoundary;
58 virtual ~nsRange();
59 explicit nsRange(nsINode* aNode);
61 public:
62 /**
63 * The following Create() returns `nsRange` instance which is initialized
64 * only with aNode. The result is never positioned.
66 static already_AddRefed<nsRange> Create(nsINode* aNode);
68 /**
69 * The following Create() may return `nsRange` instance which is initialized
70 * with given range or points. If it fails initializing new range with the
71 * arguments, returns `nullptr`. `ErrorResult` is set to an error only
72 * when this returns `nullptr`. The error code indicates the reason why
73 * it couldn't initialize the instance.
75 static already_AddRefed<nsRange> Create(const AbstractRange* aAbstractRange,
76 ErrorResult& aRv) {
77 return nsRange::Create(aAbstractRange->StartRef(), aAbstractRange->EndRef(),
78 aRv);
80 static already_AddRefed<nsRange> Create(nsINode* aStartContainer,
81 uint32_t aStartOffset,
82 nsINode* aEndContainer,
83 uint32_t aEndOffset,
84 ErrorResult& aRv) {
85 return nsRange::Create(RawRangeBoundary(aStartContainer, aStartOffset),
86 RawRangeBoundary(aEndContainer, aEndOffset), aRv);
88 template <typename SPT, typename SRT, typename EPT, typename ERT>
89 static already_AddRefed<nsRange> Create(
90 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
91 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary,
92 ErrorResult& aRv);
94 NS_DECL_ISUPPORTS_INHERITED
95 NS_IMETHODIMP_(void) DeleteCycleCollectable(void) override;
96 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsRange, AbstractRange)
98 nsrefcnt GetRefCount() const { return mRefCnt; }
100 nsINode* GetRoot() const { return mRoot; }
103 * Return true if this range was generated.
104 * @see SetIsGenerated
106 bool IsGenerated() const { return mIsGenerated; }
109 * Mark this range as being generated or not.
110 * Currently it is used for marking ranges that are created when splitting up
111 * a range to exclude a -moz-user-select:none region.
112 * @see Selection::AddRangesForSelectableNodes
113 * @see ExcludeNonSelectableNodes
115 void SetIsGenerated(bool aIsGenerated) { mIsGenerated = aIsGenerated; }
117 void Reset();
120 * SetStart() and SetEnd() sets start point or end point separately.
121 * However, this is expensive especially when it's a range of Selection.
122 * When you set both start and end of a range, you should use
123 * SetStartAndEnd() instead.
125 nsresult SetStart(nsINode* aContainer, uint32_t aOffset,
126 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
127 AllowRangeCrossShadowBoundary::No) {
128 ErrorResult error;
129 SetStart(RawRangeBoundary(aContainer, aOffset), error,
130 aAllowCrossShadowBoundary);
131 return error.StealNSResult();
133 nsresult SetEnd(nsINode* aContainer, uint32_t aOffset,
134 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
135 AllowRangeCrossShadowBoundary::No) {
136 ErrorResult error;
137 SetEnd(RawRangeBoundary(aContainer, aOffset), error,
138 aAllowCrossShadowBoundary);
139 return error.StealNSResult();
142 already_AddRefed<nsRange> CloneRange() const;
145 * SetStartAndEnd() works similar to call both SetStart() and SetEnd().
146 * Different from calls them separately, this does nothing if either
147 * the start point or the end point is invalid point.
148 * If the specified start point is after the end point, the range will be
149 * collapsed at the end point. Similarly, if they are in different root,
150 * the range will be collapsed at the end point.
152 nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
153 nsINode* aEndContainer, uint32_t aEndOffset) {
154 return SetStartAndEnd(RawRangeBoundary(aStartContainer, aStartOffset),
155 RawRangeBoundary(aEndContainer, aEndOffset));
157 template <typename SPT, typename SRT, typename EPT, typename ERT>
158 nsresult SetStartAndEnd(
159 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
160 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary) {
161 return AbstractRange::SetStartAndEndInternal(aStartBoundary, aEndBoundary,
162 this);
166 * Adds all nodes between |aStartContent| and |aEndContent| to the range.
167 * The start offset will be set before |aStartContent|,
168 * while the end offset will be set immediately after |aEndContent|.
170 * Caller must guarantee both nodes are non null and
171 * children of |aContainer| and that |aEndContent| is after |aStartContent|.
173 void SelectNodesInContainer(nsINode* aContainer, nsIContent* aStartContent,
174 nsIContent* aEndContent);
177 * CollapseTo() works similar to call both SetStart() and SetEnd() with
178 * same node and offset. This just calls SetStartAndParent() to set
179 * collapsed range at aContainer and aOffset.
181 nsresult CollapseTo(nsINode* aContainer, uint32_t aOffset) {
182 return CollapseTo(RawRangeBoundary(aContainer, aOffset));
184 nsresult CollapseTo(const RawRangeBoundary& aPoint) {
185 return SetStartAndEnd(aPoint, aPoint);
188 // aMaxRanges is the maximum number of text ranges to record for each face
189 // (pass 0 to just get the list of faces, without recording exact ranges
190 // where each face was used).
191 nsresult GetUsedFontFaces(
192 nsTArray<mozilla::UniquePtr<mozilla::dom::InspectorFontFace>>& aResult,
193 uint32_t aMaxRanges, bool aSkipCollapsedWhitespace);
195 // nsIMutationObserver methods
196 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
197 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
198 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
199 NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
200 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
202 // WebIDL
203 static already_AddRefed<nsRange> Constructor(
204 const mozilla::dom::GlobalObject& global, mozilla::ErrorResult& aRv);
206 already_AddRefed<mozilla::dom::DocumentFragment> CreateContextualFragment(
207 const nsAString& aString, ErrorResult& aError) const;
208 already_AddRefed<mozilla::dom::DocumentFragment> CloneContents(
209 ErrorResult& aErr);
210 int16_t CompareBoundaryPoints(uint16_t aHow, const nsRange& aOtherRange,
211 ErrorResult& aRv);
212 int16_t ComparePoint(const nsINode& aContainer, uint32_t aOffset,
213 ErrorResult& aRv,
214 bool aAllowCrossShadowBoundary = false) const;
215 void DeleteContents(ErrorResult& aRv);
216 already_AddRefed<mozilla::dom::DocumentFragment> ExtractContents(
217 ErrorResult& aErr);
218 nsINode* GetCommonAncestorContainer(ErrorResult& aRv) const {
219 if (!mIsPositioned) {
220 aRv.Throw(NS_ERROR_NOT_INITIALIZED);
221 return nullptr;
223 return GetClosestCommonInclusiveAncestor();
225 void InsertNode(nsINode& aNode, ErrorResult& aErr);
226 bool IntersectsNode(nsINode& aNode, ErrorResult& aRv);
227 bool IsPointInRange(const nsINode& aContainer, uint32_t aOffset,
228 ErrorResult& aRv,
229 bool aAllowCrossShadowBoundary = false) const;
230 void ToString(nsAString& aReturn, ErrorResult& aErr);
231 void Detach();
233 // *JS() methods are mapped to Range.*() of DOM.
234 // They may move focus only when the range represents normal selection.
235 // These methods shouldn't be used from internal.
236 void CollapseJS(bool aToStart);
237 void SelectNodeJS(nsINode& aNode, ErrorResult& aErr);
238 void SelectNodeContentsJS(nsINode& aNode, ErrorResult& aErr);
239 void SetEndJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
240 void SetEndAfterJS(nsINode& aNode, ErrorResult& aErr);
241 void SetEndBeforeJS(nsINode& aNode, ErrorResult& aErr);
242 void SetStartJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
243 void SetStartAfterJS(nsINode& aNode, ErrorResult& aErr);
244 void SetStartBeforeJS(nsINode& aNode, ErrorResult& aErr);
246 void SetStartAllowCrossShadowBoundary(nsINode& aNode, uint32_t aOffset,
247 ErrorResult& aErr);
248 void SetEndAllowCrossShadowBoundary(nsINode& aNode, uint32_t aOffset,
249 ErrorResult& aErr);
251 void SurroundContents(nsINode& aNode, ErrorResult& aErr);
252 already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true,
253 bool aFlushLayout = true);
254 already_AddRefed<DOMRectList> GetClientRects(bool aClampToEdge = true,
255 bool aFlushLayout = true);
256 void GetClientRectsAndTexts(mozilla::dom::ClientRectsAndTexts& aResult,
257 ErrorResult& aErr);
259 // Following methods should be used for internal use instead of *JS().
260 void SelectNode(nsINode& aNode, ErrorResult& aErr);
261 void SelectNodeContents(nsINode& aNode, ErrorResult& aErr);
262 void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr,
263 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
264 AllowRangeCrossShadowBoundary::No);
265 void SetEnd(const RawRangeBoundary& aPoint, ErrorResult& aErr,
266 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
267 AllowRangeCrossShadowBoundary::No);
268 void SetEndAfter(nsINode& aNode, ErrorResult& aErr);
269 void SetEndBefore(nsINode& aNode, ErrorResult& aErr,
270 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
271 AllowRangeCrossShadowBoundary::No);
272 void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr,
273 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
274 AllowRangeCrossShadowBoundary::No);
275 void SetStart(const RawRangeBoundary& aPoint, ErrorResult& aErr,
276 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
277 AllowRangeCrossShadowBoundary::No);
278 void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
279 void SetStartBefore(nsINode& aNode, ErrorResult& aErr,
280 AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
281 AllowRangeCrossShadowBoundary::No);
282 void Collapse(bool aToStart);
284 static void GetInnerTextNoFlush(mozilla::dom::DOMString& aValue,
285 mozilla::ErrorResult& aError,
286 nsIContent* aContainer);
288 virtual JSObject* WrapObject(JSContext* cx,
289 JS::Handle<JSObject*> aGivenProto) final;
290 DocGroup* GetDocGroup() const;
292 private:
293 // no copy's or assigns
294 nsRange(const nsRange&);
295 nsRange& operator=(const nsRange&);
297 template <typename SPT, typename SRT, typename EPT, typename ERT>
298 static void AssertIfMismatchRootAndRangeBoundaries(
299 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
300 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary,
301 const nsINode* aRootNode, bool aNotInsertedYet = false);
304 * Cut or delete the range's contents.
306 * @param aFragment DocumentFragment containing the nodes.
307 * May be null to indicate the caller doesn't want a
308 * fragment.
309 * @param aRv The error if any.
311 void CutContents(mozilla::dom::DocumentFragment** aFragment,
312 ErrorResult& aRv);
314 static nsresult CloneParentsBetween(nsINode* aAncestor, nsINode* aNode,
315 nsINode** aClosestAncestor,
316 nsINode** aFarthestAncestor);
319 * Returns whether a node is safe to be accessed by the current caller.
321 bool CanAccess(const nsINode&) const;
323 void AdjustNextRefsOnCharacterDataSplit(const nsIContent& aContent,
324 const CharacterDataChangeInfo& aInfo);
326 struct RangeBoundariesAndRoot {
327 RawRangeBoundary mStart;
328 RawRangeBoundary mEnd;
329 nsINode* mRoot = nullptr;
333 * @param aContent Must be non-nullptr.
335 RangeBoundariesAndRoot DetermineNewRangeBoundariesAndRootOnCharacterDataMerge(
336 nsIContent* aContent, const CharacterDataChangeInfo& aInfo) const;
338 // @return true iff the range is positioned, aContainer belongs to the same
339 // document as the range, aContainer is a DOCUMENT_TYPE_NODE and
340 // aOffset doesn't exceed aContainer's length.
341 bool IsPointComparableToRange(const nsINode& aContainer, uint32_t aOffset,
342 bool aAllowCrossShadowBoundary,
343 ErrorResult& aErrorResult) const;
345 // @return true iff aContainer is a shadow including inclusive descendant of
346 // the common ancestor of the mCrossBoundaryRange.
347 bool IsShadowIncludingInclusiveDescendantOfCrossBoundaryRangeAncestor(
348 const nsINode& aContainer) const;
351 * @brief Returns true if the range is part of exactly one |Selection|.
353 bool IsPartOfOneSelectionOnly() const { return mSelections.Length() == 1; };
355 public:
357 * This helper function gets rects and correlated text for the given range.
358 * @param aTextList optional where nullptr = don't retrieve text
360 static void CollectClientRectsAndText(
361 mozilla::RectCallback* aCollector,
362 mozilla::dom::Sequence<nsString>* aTextList, nsRange* aRange,
363 nsINode* aStartContainer, uint32_t aStartOffset, nsINode* aEndContainer,
364 uint32_t aEndOffset, bool aClampToEdge, bool aFlushLayout);
367 * Scan this range for -moz-user-select:none nodes and split it up into
368 * multiple ranges to exclude those nodes. The resulting ranges are put
369 * in aOutRanges. If no -moz-user-select:none node is found in the range
370 * then |this| is unmodified and is the only range in aOutRanges.
371 * Otherwise, |this| will be modified so that it ends before the first
372 * -moz-user-select:none node and additional ranges may also be created.
373 * If all nodes in the range are -moz-user-select:none then aOutRanges
374 * will be empty.
375 * @param aOutRanges the resulting set of ranges
377 void ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges);
380 * Notify the selection listeners after a range has been modified.
382 MOZ_CAN_RUN_SCRIPT void NotifySelectionListenersAfterRangeSet();
385 * For a range for which IsInSelection() is true, return the closest common
386 * inclusive ancestor
387 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor)
388 * for the range, which we had to compute when the common ancestor changed or
389 * IsInSelection became true, so we could register with it. That is, it's a
390 * faster version of GetClosestCommonInclusiveAncestor that only works for
391 * ranges in a Selection. The method will assert and the behavior is undefined
392 * if called on a range where IsInSelection() is false.
394 nsINode* GetRegisteredClosestCommonInclusiveAncestor();
396 template <typename SPT, typename SRT, typename EPT, typename ERT>
397 void CreateOrUpdateCrossShadowBoundaryRangeIfNeeded(
398 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
399 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary);
401 void ResetCrossShadowBoundaryRange() { mCrossShadowBoundaryRange = nullptr; }
403 #ifdef DEBUG
404 bool CrossShadowBoundaryRangeCollapsed() const {
405 MOZ_ASSERT(mCrossShadowBoundaryRange);
407 return !mCrossShadowBoundaryRange->IsPositioned() ||
408 (mCrossShadowBoundaryRange->GetStartContainer() ==
409 mCrossShadowBoundaryRange->GetEndContainer() &&
410 mCrossShadowBoundaryRange->StartOffset() ==
411 mCrossShadowBoundaryRange->EndOffset());
413 #endif
416 * The methods marked with MayCrossShadowBoundary[..] additionally check for
417 * the existence of mCrossShadowBoundaryRange, which indicates a range that
418 * crosses a shadow DOM boundary (i.e. mStart and mEnd are in different
419 * trees). If the caller can guarantee that this does not happen, there are
420 * additional variants of these methods named without MayCrossShadowBoundary,
421 * which provide a slightly faster implementation.
422 * */
424 nsIContent* GetMayCrossShadowBoundaryChildAtStartOffset() const {
425 return mCrossShadowBoundaryRange
426 ? mCrossShadowBoundaryRange->GetChildAtStartOffset()
427 : mStart.GetChildAtOffset();
430 nsIContent* GetMayCrossShadowBoundaryChildAtEndOffset() const {
431 return mCrossShadowBoundaryRange
432 ? mCrossShadowBoundaryRange->GetChildAtEndOffset()
433 : mEnd.GetChildAtOffset();
436 mozilla::dom::CrossShadowBoundaryRange* GetCrossShadowBoundaryRange() const {
437 return mCrossShadowBoundaryRange;
440 nsINode* GetMayCrossShadowBoundaryStartContainer() const {
441 return mCrossShadowBoundaryRange
442 ? mCrossShadowBoundaryRange->GetStartContainer()
443 : mStart.Container();
446 nsINode* GetMayCrossShadowBoundaryEndContainer() const {
447 return mCrossShadowBoundaryRange
448 ? mCrossShadowBoundaryRange->GetEndContainer()
449 : mEnd.Container();
452 uint32_t MayCrossShadowBoundaryStartOffset() const {
453 return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->StartOffset()
454 : StartOffset();
457 uint32_t MayCrossShadowBoundaryEndOffset() const {
458 return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->EndOffset()
459 : EndOffset();
462 const RangeBoundary& MayCrossShadowBoundaryStartRef() const {
463 return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->StartRef()
464 : StartRef();
467 const RangeBoundary& MayCrossShadowBoundaryEndRef() const {
468 return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->EndRef()
469 : EndRef();
472 protected:
474 * DoSetRange() is called when `AbstractRange::SetStartAndEndInternal()` sets
475 * mStart and mEnd, or some other internal methods modify `mStart` and/or
476 * `mEnd`. Therefore, this shouldn't be a virtual method.
478 * @param aStartBoundary Computed start point. This must equals or be
479 * before aEndBoundary in the DOM tree order.
480 * @param aEndBoundary Computed end point.
481 * @param aRootNode The root node.
482 * @param aNotInsertedYet true if this is called by CharacterDataChanged()
483 * to disable assertion and suppress re-registering
484 * a range common ancestor node since the new text
485 * node of a splitText hasn't been inserted yet.
486 * CharacterDataChanged() does the re-registering
487 * when needed. Otherwise, false.
489 template <typename SPT, typename SRT, typename EPT, typename ERT>
490 MOZ_CAN_RUN_SCRIPT_BOUNDARY void DoSetRange(
491 const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
492 const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary,
493 nsINode* aRootNode, bool aNotInsertedYet = false,
494 mozilla::dom::CollapsePolicy aCollapsePolicy = mozilla::dom::
495 CollapsePolicy::DefaultRangeAndCrossShadowBoundaryRanges);
497 // Assume that this is guaranteed that this is held by the caller when
498 // this is used. (Note that we cannot use AutoRestore for mCalledByJS
499 // due to a bit field.)
500 class MOZ_RAII AutoCalledByJSRestore final {
501 private:
502 nsRange& mRange;
503 bool mOldValue;
505 public:
506 explicit AutoCalledByJSRestore(nsRange& aRange)
507 : mRange(aRange), mOldValue(aRange.mCalledByJS) {}
508 ~AutoCalledByJSRestore() { mRange.mCalledByJS = mOldValue; }
509 bool SavedValue() const { return mOldValue; }
512 struct MOZ_STACK_CLASS AutoInvalidateSelection {
513 explicit AutoInvalidateSelection(nsRange* aRange) : mRange(aRange) {
514 if (!mRange->IsInAnySelection() || sIsNested) {
515 return;
517 sIsNested = true;
518 mCommonAncestor = mRange->GetRegisteredClosestCommonInclusiveAncestor();
520 ~AutoInvalidateSelection();
521 nsRange* mRange;
522 RefPtr<nsINode> mCommonAncestor;
523 static bool sIsNested;
526 bool MaybeInterruptLastRelease();
528 #ifdef DEBUG
529 bool IsCleared() const {
530 return !mRoot && !mRegisteredClosestCommonInclusiveAncestor &&
531 mSelections.IsEmpty() && !mNextStartRef && !mNextEndRef;
533 #endif // #ifdef DEBUG
535 nsCOMPtr<nsINode> mRoot;
537 // These raw pointers are used to remember a child that is about
538 // to be inserted between a CharacterData call and a subsequent
539 // ContentInserted or ContentAppended call. It is safe to store
540 // these refs because the caller is guaranteed to trigger both
541 // notifications while holding a strong reference to the new child.
542 nsIContent* MOZ_NON_OWNING_REF mNextStartRef;
543 nsIContent* MOZ_NON_OWNING_REF mNextEndRef;
545 static nsTArray<RefPtr<nsRange>>* sCachedRanges;
547 // Used to keep track of the real start and end for a
548 // selection where the start and the end are in different trees.
549 // It's NULL when the nodes are in the same tree.
551 // mCrossShadowBoundaryRange doesn't deal with DOM mutations, because
552 // it's still an open question about how it should be handled.
553 // Spec: https://github.com/w3c/selection-api/issues/168.
554 // As a result, it'll be set to NULL if that happens.
556 // Theoretically, mCrossShadowBoundaryRange isn't really needed because
557 // we should be able to always store the real start and end, and
558 // just return one point when a collapse is needed.
559 // Bug https://bugzilla.mozilla.org/show_bug.cgi?id=1886028 is going
560 // to be used to improve mCrossShadowBoundaryRange.
561 RefPtr<mozilla::dom::CrossShadowBoundaryRange> mCrossShadowBoundaryRange;
563 friend class mozilla::dom::AbstractRange;
565 namespace mozilla::dom {
566 inline nsRange* AbstractRange::AsDynamicRange() {
567 MOZ_ASSERT(IsDynamicRange());
568 return static_cast<nsRange*>(this);
570 inline const nsRange* AbstractRange::AsDynamicRange() const {
571 MOZ_ASSERT(IsDynamicRange());
572 return static_cast<const nsRange*>(this);
574 } // namespace mozilla::dom
575 #endif /* nsRange_h___ */