StaticRange.cpp (6552B)
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/. */ 6 7 #include "mozilla/dom/StaticRange.h" 8 9 #include "mozilla/dom/StaticRangeBinding.h" 10 #include "nsContentUtils.h" 11 #include "nsINode.h" 12 13 namespace mozilla::dom { 14 15 template already_AddRefed<StaticRange> StaticRange::Create( 16 const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, 17 ErrorResult& aRv); 18 template already_AddRefed<StaticRange> StaticRange::Create( 19 const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary, 20 ErrorResult& aRv); 21 template already_AddRefed<StaticRange> StaticRange::Create( 22 const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, 23 ErrorResult& aRv); 24 template already_AddRefed<StaticRange> StaticRange::Create( 25 const RawRangeBoundary& aStartBoundary, 26 const RawRangeBoundary& aEndBoundary, ErrorResult& aRv); 27 template nsresult StaticRange::SetStartAndEnd( 28 const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary); 29 template nsresult StaticRange::SetStartAndEnd( 30 const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary); 31 template nsresult StaticRange::SetStartAndEnd( 32 const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary); 33 template nsresult StaticRange::SetStartAndEnd( 34 const RawRangeBoundary& aStartBoundary, 35 const RawRangeBoundary& aEndBoundary); 36 template void StaticRange::DoSetRange(const RangeBoundary& aStartBoundary, 37 const RangeBoundary& aEndBoundary, 38 nsINode* aRootNode); 39 template void StaticRange::DoSetRange(const RangeBoundary& aStartBoundary, 40 const RawRangeBoundary& aEndBoundary, 41 nsINode* aRootNode); 42 template void StaticRange::DoSetRange(const RawRangeBoundary& aStartBoundary, 43 const RangeBoundary& aEndBoundary, 44 nsINode* aRootNode); 45 template void StaticRange::DoSetRange(const RawRangeBoundary& aStartBoundary, 46 const RawRangeBoundary& aEndBoundary, 47 nsINode* aRootNode); 48 49 nsTArray<RefPtr<StaticRange>>* StaticRange::sCachedRanges = nullptr; 50 51 NS_IMPL_CYCLE_COLLECTING_ADDREF(StaticRange) 52 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_INTERRUPTABLE_LAST_RELEASE( 53 StaticRange, DoSetRange(RawRangeBoundary(), RawRangeBoundary(), nullptr), 54 AbstractRange::MaybeCacheToReuse(*this)) 55 56 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StaticRange) 57 NS_INTERFACE_MAP_END_INHERITING(AbstractRange) 58 59 NS_IMPL_CYCLE_COLLECTION_CLASS(StaticRange) 60 61 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(StaticRange, AbstractRange) 62 NS_IMPL_CYCLE_COLLECTION_UNLINK(mStart) 63 NS_IMPL_CYCLE_COLLECTION_UNLINK(mEnd) 64 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 65 66 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(StaticRange, AbstractRange) 67 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 68 69 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(StaticRange, AbstractRange) 70 NS_IMPL_CYCLE_COLLECTION_TRACE_END 71 72 // static 73 already_AddRefed<StaticRange> StaticRange::Create(nsINode* aNode) { 74 MOZ_ASSERT(aNode); 75 if (!sCachedRanges || sCachedRanges->IsEmpty()) { 76 return do_AddRef( 77 new StaticRange(aNode, RangeBoundaryIsMutationObserved::No)); 78 } 79 RefPtr<StaticRange> staticRange = sCachedRanges->PopLastElement().forget(); 80 staticRange->Init(aNode); 81 return staticRange.forget(); 82 } 83 84 // static 85 template <typename SPT, typename SRT, typename EPT, typename ERT> 86 already_AddRefed<StaticRange> StaticRange::Create( 87 const RangeBoundaryBase<SPT, SRT>& aStartBoundary, 88 const RangeBoundaryBase<EPT, ERT>& aEndBoundary, ErrorResult& aRv) { 89 RefPtr<StaticRange> staticRange = 90 StaticRange::Create(aStartBoundary.GetContainer()); 91 staticRange->DoSetRange(aStartBoundary, aEndBoundary, nullptr); 92 93 return staticRange.forget(); 94 } 95 96 StaticRange::~StaticRange() { 97 DoSetRange(RawRangeBoundary(mStart.GetTreeKind()), 98 RawRangeBoundary(mEnd.GetTreeKind()), nullptr); 99 } 100 101 bool StaticRange::IsValid() const { 102 if (!mStart.IsSetAndValid() || !mEnd.IsSetAndValid()) { 103 return false; 104 } 105 106 MOZ_ASSERT(mAreStartAndEndInSameTree == 107 (RangeUtils::ComputeRootNode(mStart.GetContainer()) == 108 RangeUtils::ComputeRootNode(mEnd.GetContainer()))); 109 if (!mAreStartAndEndInSameTree) { 110 return false; 111 } 112 113 const Maybe<int32_t> pointOrder = nsContentUtils::ComparePoints(mStart, mEnd); 114 return pointOrder.isSome() && *pointOrder <= 0; 115 } 116 117 template <typename SPT, typename SRT, typename EPT, typename ERT> 118 void StaticRange::DoSetRange(const RangeBoundaryBase<SPT, SRT>& aStartBoundary, 119 const RangeBoundaryBase<EPT, ERT>& aEndBoundary, 120 nsINode* aRootNode) { 121 bool checkCommonAncestor = 122 IsInAnySelection() && 123 (mStart.GetContainer() != aStartBoundary.GetContainer() || 124 mEnd.GetContainer() != aEndBoundary.GetContainer()); 125 mStart.CopyFrom(aStartBoundary, mIsMutationObserved); 126 mEnd.CopyFrom(aEndBoundary, mIsMutationObserved); 127 MOZ_ASSERT(mStart.IsSet() == mEnd.IsSet()); 128 mIsPositioned = mStart.IsSet() && mEnd.IsSet(); 129 130 if (checkCommonAncestor) { 131 UpdateCommonAncestorIfNecessary(); 132 } 133 134 mAreStartAndEndInSameTree = 135 RangeUtils::ComputeRootNode(mStart.GetContainer()) == 136 RangeUtils::ComputeRootNode(mEnd.GetContainer()); 137 } 138 139 /* static */ 140 already_AddRefed<StaticRange> StaticRange::Constructor( 141 const GlobalObject& global, const StaticRangeInit& init, ErrorResult& aRv) { 142 if (init.mStartContainer->NodeType() == nsINode::DOCUMENT_TYPE_NODE || 143 init.mStartContainer->NodeType() == nsINode::ATTRIBUTE_NODE || 144 init.mEndContainer->NodeType() == nsINode::DOCUMENT_TYPE_NODE || 145 init.mEndContainer->NodeType() == nsINode::ATTRIBUTE_NODE) { 146 aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); 147 return nullptr; 148 } 149 150 return Create(init.mStartContainer, init.mStartOffset, init.mEndContainer, 151 init.mEndOffset, aRv); 152 } 153 154 JSObject* StaticRange::WrapObject(JSContext* aCx, 155 JS::Handle<JSObject*> aGivenProto) { 156 return StaticRange_Binding::Wrap(aCx, this, aGivenProto); 157 } 158 159 } // namespace mozilla::dom