forked from mirrors/gecko-dev
		
	 cd7eee028b
			
		
	
	
		cd7eee028b
		
	
	
	
	
		
			
			So that when a node is removed and this node is related to the start or the end point of the `CrossShadowBoundaryRange`, we can clear this `CrossShadowBoundaryRange`. We clear it for now because we aren't sure about what the new points should be. `nsRange` does a similar thing to `mRoot`, and we can't rely on `nsRange` to observer `mRoot` because `mRoot` could be root of a collapsed range, so it's not the root of `CrossShadowBoundaryRange`. Differential Revision: https://phabricator.services.mozilla.com/D211246
		
			
				
	
	
		
			168 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "mozilla/dom/CrossShadowBoundaryRange.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsINode.h"
 | |
| #include "nsRange.h"
 | |
| #include "nsIContentInlines.h"
 | |
| 
 | |
| namespace mozilla::dom {
 | |
| template already_AddRefed<CrossShadowBoundaryRange>
 | |
| CrossShadowBoundaryRange::Create(const RangeBoundary& aStartBoundary,
 | |
|                                  const RangeBoundary& aEndBoundary,
 | |
|                                  nsRange* aOwner);
 | |
| template already_AddRefed<CrossShadowBoundaryRange>
 | |
| CrossShadowBoundaryRange::Create(const RangeBoundary& aStartBoundary,
 | |
|                                  const RawRangeBoundary& aEndBoundary,
 | |
|                                  nsRange* aOwner);
 | |
| template already_AddRefed<CrossShadowBoundaryRange>
 | |
| CrossShadowBoundaryRange::Create(const RawRangeBoundary& aStartBoundary,
 | |
|                                  const RangeBoundary& aEndBoundary,
 | |
|                                  nsRange* aOwner);
 | |
| template already_AddRefed<CrossShadowBoundaryRange>
 | |
| CrossShadowBoundaryRange::Create(const RawRangeBoundary& aStartBoundary,
 | |
|                                  const RawRangeBoundary& aEndBoundary,
 | |
|                                  nsRange* aOwner);
 | |
| 
 | |
| template void CrossShadowBoundaryRange::DoSetRange(
 | |
|     const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary,
 | |
|     nsINode* aRootNode, nsRange* aOwner);
 | |
| template void CrossShadowBoundaryRange::DoSetRange(
 | |
|     const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary,
 | |
|     nsINode* aRootNode, nsRange* aOwner);
 | |
| template void CrossShadowBoundaryRange::DoSetRange(
 | |
|     const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary,
 | |
|     nsINode* aRootNode, nsRange* aOwner);
 | |
| template void CrossShadowBoundaryRange::DoSetRange(
 | |
|     const RawRangeBoundary& aStartBoundary,
 | |
|     const RawRangeBoundary& aEndBoundary, nsINode* aRootNode, nsRange* aOwner);
 | |
| 
 | |
| template nsresult CrossShadowBoundaryRange::SetStartAndEnd(
 | |
|     const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary);
 | |
| template nsresult CrossShadowBoundaryRange::SetStartAndEnd(
 | |
|     const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary);
 | |
| template nsresult CrossShadowBoundaryRange::SetStartAndEnd(
 | |
|     const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary);
 | |
| template nsresult CrossShadowBoundaryRange::SetStartAndEnd(
 | |
|     const RawRangeBoundary& aStartBoundary,
 | |
|     const RawRangeBoundary& aEndBoundary);
 | |
| 
 | |
| nsTArray<RefPtr<CrossShadowBoundaryRange>>*
 | |
|     CrossShadowBoundaryRange::sCachedRanges = nullptr;
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTING_ADDREF(CrossShadowBoundaryRange)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_INTERRUPTABLE_LAST_RELEASE(
 | |
|     CrossShadowBoundaryRange,
 | |
|     DoSetRange(RawRangeBoundary(), RawRangeBoundary(), nullptr, nullptr),
 | |
|     AbstractRange::MaybeCacheToReuse(*this))
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CrossShadowBoundaryRange)
 | |
| NS_INTERFACE_MAP_END_INHERITING(CrossShadowBoundaryRange)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_CLASS(CrossShadowBoundaryRange)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CrossShadowBoundaryRange,
 | |
|                                                 StaticRange)
 | |
|   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommonAncestor)
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CrossShadowBoundaryRange,
 | |
|                                                   StaticRange)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommonAncestor)
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(CrossShadowBoundaryRange,
 | |
|                                                StaticRange)
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_END
 | |
| 
 | |
| /* static */
 | |
| template <typename SPT, typename SRT, typename EPT, typename ERT>
 | |
| already_AddRefed<CrossShadowBoundaryRange> CrossShadowBoundaryRange::Create(
 | |
|     const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
 | |
|     const RangeBoundaryBase<EPT, ERT>& aEndBoundary, nsRange* aOwner) {
 | |
|   RefPtr<CrossShadowBoundaryRange> range;
 | |
|   if (!sCachedRanges || sCachedRanges->IsEmpty()) {
 | |
|     range = new CrossShadowBoundaryRange(aStartBoundary.Container(), aOwner);
 | |
|   } else {
 | |
|     range = sCachedRanges->PopLastElement().forget();
 | |
|   }
 | |
| 
 | |
|   range->Init(aStartBoundary.Container());
 | |
|   range->DoSetRange(aStartBoundary, aEndBoundary, nullptr, aOwner);
 | |
|   return range.forget();
 | |
| }
 | |
| 
 | |
| template <typename SPT, typename SRT, typename EPT, typename ERT>
 | |
| void CrossShadowBoundaryRange::DoSetRange(
 | |
|     const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
 | |
|     const RangeBoundaryBase<EPT, ERT>& aEndBoundary, nsINode* aRootNode,
 | |
|     nsRange* aOwner) {
 | |
|   // aRootNode is useless to CrossShadowBoundaryRange because aStartBoundary
 | |
|   // and aEndBoundary could have different roots.
 | |
|   StaticRange::DoSetRange(aStartBoundary, aEndBoundary, nullptr);
 | |
| 
 | |
|   nsINode* startRoot = RangeUtils::ComputeRootNode(mStart.Container());
 | |
|   nsINode* endRoot = RangeUtils::ComputeRootNode(mEnd.Container());
 | |
| 
 | |
|   nsINode* previousCommonAncestor = mCommonAncestor;
 | |
|   if (startRoot == endRoot) {
 | |
|     MOZ_ASSERT(!startRoot && !endRoot);
 | |
|     MOZ_ASSERT(!aOwner);
 | |
|     // This should be the case when Release() is called.
 | |
|     mCommonAncestor = startRoot;
 | |
|     mOwner = nullptr;
 | |
|   } else {
 | |
|     mCommonAncestor =
 | |
|         nsContentUtils::GetClosestCommonShadowIncludingInclusiveAncestor(
 | |
|             mStart.Container(), mEnd.Container());
 | |
|     MOZ_ASSERT_IF(mOwner, mOwner == aOwner);
 | |
|     if (!mOwner) {
 | |
|       mOwner = aOwner;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (previousCommonAncestor != mCommonAncestor) {
 | |
|     if (previousCommonAncestor) {
 | |
|       previousCommonAncestor->RemoveMutationObserver(this);
 | |
|     }
 | |
|     if (mCommonAncestor) {
 | |
|       mCommonAncestor->AddMutationObserver(this);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| void CrossShadowBoundaryRange::ContentRemoved(nsIContent* aChild,
 | |
|                                               nsIContent* aPreviousSibling) {
 | |
|   // It's unclear from the spec about what should the selection be after
 | |
|   // DOM mutation. See https://github.com/w3c/selection-api/issues/168
 | |
|   //
 | |
|   // For now, we just clear the selection if the removed node is related
 | |
|   // to mStart or mEnd.
 | |
|   MOZ_DIAGNOSTIC_ASSERT(mOwner);
 | |
|   MOZ_DIAGNOSTIC_ASSERT(mOwner->GetCrossShadowBoundaryRange() == this);
 | |
| 
 | |
|   RefPtr<CrossShadowBoundaryRange> kungFuDeathGrip(this);
 | |
| 
 | |
|   if (mStart.Container() == aChild || mEnd.Container() == aChild) {
 | |
|     mOwner->ResetCrossShadowBoundaryRange();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (const auto* shadowRoot = aChild->GetShadowRoot()) {
 | |
|     if (mStart.Container() == shadowRoot || mEnd.Container() == shadowRoot) {
 | |
|       mOwner->ResetCrossShadowBoundaryRange();
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (mStart.Container()->IsShadowIncludingInclusiveDescendantOf(aChild) ||
 | |
|       mEnd.Container()->IsShadowIncludingInclusiveDescendantOf(aChild)) {
 | |
|     mOwner->ResetCrossShadowBoundaryRange();
 | |
|     return;
 | |
|   }
 | |
| }
 | |
| }  // namespace mozilla::dom
 |