summaryrefslogtreecommitdiffstats
path: root/dom/base/nsRange.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/nsRange.h')
-rw-r--r--dom/base/nsRange.h149
1 files changed, 138 insertions, 11 deletions
diff --git a/dom/base/nsRange.h b/dom/base/nsRange.h
index 97756d3afc..94459087cb 100644
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -13,6 +13,7 @@
#include "nsCOMPtr.h"
#include "mozilla/dom/AbstractRange.h"
+#include "mozilla/dom/StaticRange.h"
#include "prmon.h"
#include "nsStubMutationObserver.h"
#include "nsWrapperCache.h"
@@ -31,6 +32,13 @@ class DOMRect;
class DOMRectList;
class InspectorFontFace;
class Selection;
+
+enum class CollapsePolicy : uint8_t {
+ No, // Don't need to collapse
+ DefaultRange, // Collapse the default range
+ DefaultRangeAndCrossShadowBoundaryRanges // Collapse both the default range
+ // and the cross boundary range
+};
} // namespace dom
} // namespace mozilla
@@ -43,6 +51,8 @@ class nsRange final : public mozilla::dom::AbstractRange,
using DOMRectList = mozilla::dom::DOMRectList;
using RangeBoundary = mozilla::RangeBoundary;
using RawRangeBoundary = mozilla::RawRangeBoundary;
+ using AllowRangeCrossShadowBoundary =
+ mozilla::dom::AllowRangeCrossShadowBoundary;
virtual ~nsRange();
explicit nsRange(nsINode* aNode);
@@ -111,14 +121,20 @@ class nsRange final : public mozilla::dom::AbstractRange,
* When you set both start and end of a range, you should use
* SetStartAndEnd() instead.
*/
- nsresult SetStart(nsINode* aContainer, uint32_t aOffset) {
+ nsresult SetStart(nsINode* aContainer, uint32_t aOffset,
+ AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
+ AllowRangeCrossShadowBoundary::No) {
ErrorResult error;
- SetStart(RawRangeBoundary(aContainer, aOffset), error);
+ SetStart(RawRangeBoundary(aContainer, aOffset), error,
+ aAllowCrossShadowBoundary);
return error.StealNSResult();
}
- nsresult SetEnd(nsINode* aContainer, uint32_t aOffset) {
+ nsresult SetEnd(nsINode* aContainer, uint32_t aOffset,
+ AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
+ AllowRangeCrossShadowBoundary::No) {
ErrorResult error;
- SetEnd(RawRangeBoundary(aContainer, aOffset), error);
+ SetEnd(RawRangeBoundary(aContainer, aOffset), error,
+ aAllowCrossShadowBoundary);
return error.StealNSResult();
}
@@ -224,6 +240,11 @@ class nsRange final : public mozilla::dom::AbstractRange,
void SetStartAfterJS(nsINode& aNode, ErrorResult& aErr);
void SetStartBeforeJS(nsINode& aNode, ErrorResult& aErr);
+ void SetStartAllowCrossShadowBoundary(nsINode& aNode, uint32_t aOffset,
+ ErrorResult& aErr);
+ void SetEndAllowCrossShadowBoundary(nsINode& aNode, uint32_t aOffset,
+ ErrorResult& aErr);
+
void SurroundContents(nsINode& aNode, ErrorResult& aErr);
already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true,
bool aFlushLayout = true);
@@ -235,14 +256,26 @@ class nsRange final : public mozilla::dom::AbstractRange,
// Following methods should be used for internal use instead of *JS().
void SelectNode(nsINode& aNode, ErrorResult& aErr);
void SelectNodeContents(nsINode& aNode, ErrorResult& aErr);
- void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
- void SetEnd(const RawRangeBoundary& aPoint, ErrorResult& aErr);
+ void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr,
+ AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
+ AllowRangeCrossShadowBoundary::No);
+ void SetEnd(const RawRangeBoundary& aPoint, ErrorResult& aErr,
+ AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
+ AllowRangeCrossShadowBoundary::No);
void SetEndAfter(nsINode& aNode, ErrorResult& aErr);
- void SetEndBefore(nsINode& aNode, ErrorResult& aErr);
- void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
- void SetStart(const RawRangeBoundary& aPoint, ErrorResult& aErr);
+ void SetEndBefore(nsINode& aNode, ErrorResult& aErr,
+ AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
+ AllowRangeCrossShadowBoundary::No);
+ void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr,
+ AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
+ AllowRangeCrossShadowBoundary::No);
+ void SetStart(const RawRangeBoundary& aPoint, ErrorResult& aErr,
+ AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
+ AllowRangeCrossShadowBoundary::No);
void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
- void SetStartBefore(nsINode& aNode, ErrorResult& aErr);
+ void SetStartBefore(nsINode& aNode, ErrorResult& aErr,
+ AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
+ AllowRangeCrossShadowBoundary::No);
void Collapse(bool aToStart);
static void GetInnerTextNoFlush(mozilla::dom::DOMString& aValue,
@@ -351,6 +384,82 @@ class nsRange final : public mozilla::dom::AbstractRange,
*/
nsINode* GetRegisteredClosestCommonInclusiveAncestor();
+ template <typename SPT, typename SRT, typename EPT, typename ERT>
+ void CreateOrUpdateCrossShadowBoundaryRangeIfNeeded(
+ const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
+ const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary);
+
+ void ResetCrossShadowBoundaryRange() { mCrossShadowBoundaryRange = nullptr; }
+
+#ifdef DEBUG
+ bool CrossShadowBoundaryRangeCollapsed() const {
+ MOZ_ASSERT(mCrossShadowBoundaryRange);
+
+ return !mCrossShadowBoundaryRange->IsPositioned() ||
+ (mCrossShadowBoundaryRange->GetStartContainer() ==
+ mCrossShadowBoundaryRange->GetEndContainer() &&
+ mCrossShadowBoundaryRange->StartOffset() ==
+ mCrossShadowBoundaryRange->EndOffset());
+ }
+#endif
+
+ /*
+ * The methods marked with MayCrossShadowBoundary[..] additionally check for
+ * the existence of mCrossShadowBoundaryRange, which indicates a range that
+ * crosses a shadow DOM boundary (i.e. mStart and mEnd are in different
+ * trees). If the caller can guarantee that this does not happen, there are
+ * additional variants of these methods named without MayCrossShadowBoundary,
+ * which provide a slightly faster implementation.
+ * */
+
+ nsIContent* GetMayCrossShadowBoundaryChildAtStartOffset() const {
+ return mCrossShadowBoundaryRange
+ ? mCrossShadowBoundaryRange->GetChildAtStartOffset()
+ : mStart.GetChildAtOffset();
+ }
+
+ nsIContent* GetMayCrossShadowBoundaryChildAtEndOffset() const {
+ return mCrossShadowBoundaryRange
+ ? mCrossShadowBoundaryRange->GetChildAtEndOffset()
+ : mEnd.GetChildAtOffset();
+ }
+
+ mozilla::dom::StaticRange* GetCrossShadowBoundaryRange() const {
+ return mCrossShadowBoundaryRange;
+ }
+
+ nsINode* GetMayCrossShadowBoundaryStartContainer() const {
+ return mCrossShadowBoundaryRange
+ ? mCrossShadowBoundaryRange->GetStartContainer()
+ : mStart.Container();
+ }
+
+ nsINode* GetMayCrossShadowBoundaryEndContainer() const {
+ return mCrossShadowBoundaryRange
+ ? mCrossShadowBoundaryRange->GetEndContainer()
+ : mEnd.Container();
+ }
+
+ uint32_t MayCrossShadowBoundaryStartOffset() const {
+ return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->StartOffset()
+ : StartOffset();
+ }
+
+ uint32_t MayCrossShadowBoundaryEndOffset() const {
+ return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->EndOffset()
+ : EndOffset();
+ }
+
+ const RangeBoundary& MayCrossShadowBoundaryStartRef() const {
+ return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->StartRef()
+ : StartRef();
+ }
+
+ const RangeBoundary& MayCrossShadowBoundaryEndRef() const {
+ return mCrossShadowBoundaryRange ? mCrossShadowBoundaryRange->EndRef()
+ : EndRef();
+ }
+
protected:
/**
* DoSetRange() is called when `AbstractRange::SetStartAndEndInternal()` sets
@@ -372,7 +481,9 @@ class nsRange final : public mozilla::dom::AbstractRange,
MOZ_CAN_RUN_SCRIPT_BOUNDARY void DoSetRange(
const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary,
- nsINode* aRootNode, bool aNotInsertedYet = false);
+ nsINode* aRootNode, bool aNotInsertedYet = false,
+ mozilla::dom::CollapsePolicy aCollapsePolicy = mozilla::dom::
+ CollapsePolicy::DefaultRangeAndCrossShadowBoundaryRanges);
// Assume that this is guaranteed that this is held by the caller when
// this is used. (Note that we cannot use AutoRestore for mCalledByJS
@@ -424,6 +535,22 @@ class nsRange final : public mozilla::dom::AbstractRange,
static nsTArray<RefPtr<nsRange>>* sCachedRanges;
+ // Used to keep track of the real start and end for a
+ // selection where the start and the end are in different trees.
+ // It's NULL when the nodes are in the same tree.
+ //
+ // mCrossShadowBoundaryRange doesn't deal with DOM mutations, because
+ // it's still an open question about how it should be handled.
+ // Spec: https://github.com/w3c/selection-api/issues/168.
+ // As a result, it'll be set to NULL if that happens.
+ //
+ // Theoretically, mCrossShadowBoundaryRange isn't really needed because
+ // we should be able to always store the real start and end, and
+ // just return one point when a collapse is needed.
+ // Bug https://bugzilla.mozilla.org/show_bug.cgi?id=1886028 is going
+ // to be used to improve mCrossShadowBoundaryRange.
+ RefPtr<mozilla::dom::StaticRange> mCrossShadowBoundaryRange;
+
friend class mozilla::dom::AbstractRange;
};
namespace mozilla::dom {