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 #ifndef mozilla_dom_StaticRange_h
8 #define mozilla_dom_StaticRange_h
9 
10 #include "mozilla/ErrorResult.h"
11 #include "mozilla/RangeBoundary.h"
12 #include "mozilla/dom/AbstractRange.h"
13 #include "mozilla/dom/StaticRangeBinding.h"
14 #include "nsTArray.h"
15 #include "nsWrapperCache.h"
16 
17 namespace mozilla {
18 namespace dom {
19 
20 class StaticRange final : public AbstractRange {
21  public:
22   StaticRange() = delete;
23   explicit StaticRange(const StaticRange& aOther) = delete;
24 
25   static already_AddRefed<StaticRange> Constructor(const GlobalObject& global,
26                                                    const StaticRangeInit& init,
27                                                    ErrorResult& aRv);
28 
29   /**
30    * The following Create() returns `nsRange` instance which is initialized
31    * only with aNode.  The result is never positioned.
32    */
33   static already_AddRefed<StaticRange> Create(nsINode* aNode);
34 
35   /**
36    * Create() may return `StaticRange` instance which is initialized with
37    * given range or points.  If it fails initializing new range with the
38    * arguments, returns `nullptr`.  `ErrorResult` is set to an error only
39    * when this returns `nullptr`.  The error code indicates the reason why
40    * it couldn't initialize the instance.
41    */
Create(const AbstractRange * aAbstractRange,ErrorResult & aRv)42   static already_AddRefed<StaticRange> Create(
43       const AbstractRange* aAbstractRange, ErrorResult& aRv) {
44     MOZ_ASSERT(aAbstractRange);
45     return StaticRange::Create(aAbstractRange->StartRef(),
46                                aAbstractRange->EndRef(), aRv);
47   }
Create(nsINode * aStartContainer,uint32_t aStartOffset,nsINode * aEndContainer,uint32_t aEndOffset,ErrorResult & aRv)48   static already_AddRefed<StaticRange> Create(nsINode* aStartContainer,
49                                               uint32_t aStartOffset,
50                                               nsINode* aEndContainer,
51                                               uint32_t aEndOffset,
52                                               ErrorResult& aRv) {
53     return StaticRange::Create(RawRangeBoundary(aStartContainer, aStartOffset),
54                                RawRangeBoundary(aEndContainer, aEndOffset),
55                                aRv);
56   }
57   template <typename SPT, typename SRT, typename EPT, typename ERT>
58   static already_AddRefed<StaticRange> Create(
59       const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
60       const RangeBoundaryBase<EPT, ERT>& aEndBoundary, ErrorResult& aRv);
61 
62  protected:
StaticRange(nsINode * aNode)63   explicit StaticRange(nsINode* aNode) : AbstractRange(aNode) {}
64   virtual ~StaticRange() = default;
65 
66  public:
67   NS_DECL_ISUPPORTS_INHERITED
68   NS_IMETHODIMP_(void) DeleteCycleCollectable(void) override;
69   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(StaticRange,
70                                                          AbstractRange)
71 
72   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
73 
74   /**
75    * SetStartAndEnd() works similar to call both SetStart() and SetEnd().
76    * Different from calls them separately, this does nothing if either
77    * the start point or the end point is invalid point.
78    * If the specified start point is after the end point, the range will be
79    * collapsed at the end point.  Similarly, if they are in different root,
80    * the range will be collapsed at the end point.
81    */
SetStartAndEnd(nsINode * aStartContainer,uint32_t aStartOffset,nsINode * aEndContainer,uint32_t aEndOffset)82   nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
83                           nsINode* aEndContainer, uint32_t aEndOffset) {
84     return SetStartAndEnd(RawRangeBoundary(aStartContainer, aStartOffset),
85                           RawRangeBoundary(aEndContainer, aEndOffset));
86   }
87   template <typename SPT, typename SRT, typename EPT, typename ERT>
SetStartAndEnd(const RangeBoundaryBase<SPT,SRT> & aStartBoundary,const RangeBoundaryBase<EPT,ERT> & aEndBoundary)88   nsresult SetStartAndEnd(const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
89                           const RangeBoundaryBase<EPT, ERT>& aEndBoundary) {
90     return AbstractRange::SetStartAndEndInternal(aStartBoundary, aEndBoundary,
91                                                  this);
92   }
93 
94  protected:
95   /**
96    * DoSetRange() is called when `AbstractRange::SetStartAndEndInternal()` sets
97    * mStart and mEnd.
98    *
99    * @param aStartBoundary  Computed start point.  This must equals or be before
100    *                        aEndBoundary in the DOM tree order.
101    * @param aEndBoundary    Computed end point.
102    * @param aRootNode       The root node.
103    */
104   template <typename SPT, typename SRT, typename EPT, typename ERT>
105   void DoSetRange(const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
106                   const RangeBoundaryBase<EPT, ERT>& aEndBoundary,
107                   nsINode* aRootNode);
108 
109   static nsTArray<RefPtr<StaticRange>>* sCachedRanges;
110 
111   friend class AbstractRange;
112 };
113 
114 }  // namespace dom
115 }  // namespace mozilla
116 
117 #endif  // #ifndef mozilla_dom_StaticRange_h
118