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
;
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
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
;
59 explicit nsRange(nsINode
* aNode
);
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
);
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
,
77 return nsRange::Create(aAbstractRange
->StartRef(), aAbstractRange
->EndRef(),
80 static already_AddRefed
<nsRange
> Create(nsINode
* aStartContainer
,
81 uint32_t aStartOffset
,
82 nsINode
* aEndContainer
,
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
,
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
; }
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
) {
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
) {
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
,
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
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(
210 int16_t CompareBoundaryPoints(uint16_t aHow
, const nsRange
& aOtherRange
,
212 int16_t ComparePoint(const nsINode
& aContainer
, uint32_t aOffset
,
214 bool aAllowCrossShadowBoundary
= false) const;
215 void DeleteContents(ErrorResult
& aRv
);
216 already_AddRefed
<mozilla::dom::DocumentFragment
> ExtractContents(
218 nsINode
* GetCommonAncestorContainer(ErrorResult
& aRv
) const {
219 if (!mIsPositioned
) {
220 aRv
.Throw(NS_ERROR_NOT_INITIALIZED
);
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
,
229 bool aAllowCrossShadowBoundary
= false) const;
230 void ToString(nsAString
& aReturn
, ErrorResult
& aErr
);
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
,
248 void SetEndAllowCrossShadowBoundary(nsINode
& aNode
, uint32_t aOffset
,
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
,
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;
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
309 * @param aRv The error if any.
311 void CutContents(mozilla::dom::DocumentFragment
** aFragment
,
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; };
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
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
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; }
404 bool CrossShadowBoundaryRangeCollapsed() const {
405 MOZ_ASSERT(mCrossShadowBoundaryRange
);
407 return !mCrossShadowBoundaryRange
->IsPositioned() ||
408 (mCrossShadowBoundaryRange
->GetStartContainer() ==
409 mCrossShadowBoundaryRange
->GetEndContainer() &&
410 mCrossShadowBoundaryRange
->StartOffset() ==
411 mCrossShadowBoundaryRange
->EndOffset());
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.
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()
452 uint32_t MayCrossShadowBoundaryStartOffset() const {
453 return mCrossShadowBoundaryRange
? mCrossShadowBoundaryRange
->StartOffset()
457 uint32_t MayCrossShadowBoundaryEndOffset() const {
458 return mCrossShadowBoundaryRange
? mCrossShadowBoundaryRange
->EndOffset()
462 const RangeBoundary
& MayCrossShadowBoundaryStartRef() const {
463 return mCrossShadowBoundaryRange
? mCrossShadowBoundaryRange
->StartRef()
467 const RangeBoundary
& MayCrossShadowBoundaryEndRef() const {
468 return mCrossShadowBoundaryRange
? mCrossShadowBoundaryRange
->EndRef()
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
{
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
) {
518 mCommonAncestor
= mRange
->GetRegisteredClosestCommonInclusiveAncestor();
520 ~AutoInvalidateSelection();
522 RefPtr
<nsINode
> mCommonAncestor
;
523 static bool sIsNested
;
526 bool MaybeInterruptLastRelease();
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___ */