1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : * Implementation of the DOM nsIDOMRange object.
40 : */
41 :
42 : #ifndef nsRange_h___
43 : #define nsRange_h___
44 :
45 : #include "nsIDOMRange.h"
46 : #include "nsCOMPtr.h"
47 : #include "nsIDOMDocumentFragment.h"
48 : #include "nsIContent.h"
49 : #include "nsIDOMNode.h"
50 : #include "prmon.h"
51 : #include "nsStubMutationObserver.h"
52 :
53 : class nsRange : public nsIDOMRange,
54 : public nsStubMutationObserver
55 : {
56 : public:
57 0 : nsRange()
58 : : mRoot(nsnull)
59 : , mStartOffset(0)
60 : , mEndOffset(0)
61 : , mIsPositioned(false)
62 : , mIsDetached(false)
63 : , mMaySpanAnonymousSubtrees(false)
64 0 : , mInSelection(false)
65 0 : {}
66 : virtual ~nsRange();
67 :
68 : static nsresult CreateRange(nsIDOMNode* aStartParent, PRInt32 aStartOffset,
69 : nsIDOMNode* aEndParent, PRInt32 aEndOffset,
70 : nsRange** aRange);
71 : static nsresult CreateRange(nsIDOMNode* aStartParent, PRInt32 aStartOffset,
72 : nsIDOMNode* aEndParent, PRInt32 aEndOffset,
73 : nsIDOMRange** aRange);
74 :
75 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
76 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsRange, nsIDOMRange)
77 :
78 : // nsIDOMRange interface
79 : NS_DECL_NSIDOMRANGE
80 :
81 : nsINode* GetRoot() const
82 : {
83 : return mRoot;
84 : }
85 :
86 0 : nsINode* GetStartParent() const
87 : {
88 0 : return mStartParent;
89 : }
90 :
91 0 : nsINode* GetEndParent() const
92 : {
93 0 : return mEndParent;
94 : }
95 :
96 0 : PRInt32 StartOffset() const
97 : {
98 0 : return mStartOffset;
99 : }
100 :
101 0 : PRInt32 EndOffset() const
102 : {
103 0 : return mEndOffset;
104 : }
105 :
106 : bool IsPositioned() const
107 : {
108 : return mIsPositioned;
109 : }
110 :
111 : bool IsDetached() const
112 : {
113 : return mIsDetached;
114 : }
115 :
116 0 : bool Collapsed() const
117 : {
118 0 : return mIsPositioned && mStartParent == mEndParent &&
119 0 : mStartOffset == mEndOffset;
120 : }
121 :
122 0 : void SetMaySpanAnonymousSubtrees(bool aMaySpanAnonymousSubtrees)
123 : {
124 0 : mMaySpanAnonymousSubtrees = aMaySpanAnonymousSubtrees;
125 0 : }
126 :
127 : /**
128 : * Return true iff this range is part of at least one Selection object
129 : * and isn't detached.
130 : */
131 : bool IsInSelection() const
132 : {
133 : return mInSelection;
134 : }
135 :
136 : /**
137 : * Called when the range is added/removed from a Selection.
138 : */
139 : void SetInSelection(bool aInSelection)
140 : {
141 : if (mInSelection == aInSelection || mIsDetached) {
142 : return;
143 : }
144 : mInSelection = aInSelection;
145 : nsINode* commonAncestor = GetCommonAncestor();
146 : NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
147 : if (mInSelection) {
148 : RegisterCommonAncestor(commonAncestor);
149 : } else {
150 : UnregisterCommonAncestor(commonAncestor);
151 : }
152 : }
153 :
154 : nsINode* GetCommonAncestor() const;
155 : void Reset();
156 : nsresult SetStart(nsINode* aParent, PRInt32 aOffset);
157 : nsresult SetEnd(nsINode* aParent, PRInt32 aOffset);
158 : nsresult CloneRange(nsRange** aNewRange) const;
159 :
160 0 : nsresult Set(nsINode* aStartParent, PRInt32 aStartOffset,
161 : nsINode* aEndParent, PRInt32 aEndOffset)
162 : {
163 : // If this starts being hot, we may be able to optimize this a bit,
164 : // but for now just set start and end separately.
165 0 : nsresult rv = SetStart(aStartParent, aStartOffset);
166 0 : NS_ENSURE_SUCCESS(rv, rv);
167 :
168 0 : return SetEnd(aEndParent, aEndOffset);
169 : }
170 :
171 : NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult);
172 :
173 : // nsIMutationObserver methods
174 : NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
175 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
176 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
177 : NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
178 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
179 :
180 : private:
181 : // no copy's or assigns
182 : nsRange(const nsRange&);
183 : nsRange& operator=(const nsRange&);
184 :
185 : /**
186 : * Cut or delete the range's contents.
187 : *
188 : * @param aFragment nsIDOMDocumentFragment containing the nodes.
189 : * May be null to indicate the caller doesn't want a fragment.
190 : */
191 : nsresult CutContents(nsIDOMDocumentFragment** frag);
192 :
193 : static nsresult CloneParentsBetween(nsIDOMNode *aAncestor,
194 : nsIDOMNode *aNode,
195 : nsIDOMNode **aClosestAncestor,
196 : nsIDOMNode **aFarthestAncestor);
197 :
198 : public:
199 : /******************************************************************************
200 : * Utility routine to detect if a content node starts before a range and/or
201 : * ends after a range. If neither it is contained inside the range.
202 : *
203 : * XXX - callers responsibility to ensure node in same doc as range!
204 : *
205 : *****************************************************************************/
206 : static nsresult CompareNodeToRange(nsINode* aNode, nsRange* aRange,
207 : bool *outNodeBefore,
208 : bool *outNodeAfter);
209 :
210 : static bool IsNodeSelected(nsINode* aNode, PRUint32 aStartOffset,
211 : PRUint32 aEndOffset);
212 :
213 : typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
214 : protected:
215 : void RegisterCommonAncestor(nsINode* aNode);
216 : void UnregisterCommonAncestor(nsINode* aNode);
217 : nsINode* IsValidBoundary(nsINode* aNode);
218 :
219 : // CharacterDataChanged set aNotInsertedYet to true to disable an assertion
220 : // and suppress re-registering a range common ancestor node since
221 : // the new text node of a splitText hasn't been inserted yet.
222 : // CharacterDataChanged does the re-registering when needed.
223 : void DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
224 : nsINode* aEndN, PRInt32 aEndOffset,
225 : nsINode* aRoot, bool aNotInsertedYet = false);
226 :
227 : /**
228 : * For a range for which IsInSelection() is true, return the common
229 : * ancestor for the range. This method uses the selection bits and
230 : * nsGkAtoms::range property on the nodes to quickly find the ancestor.
231 : * That is, it's a faster version of GetCommonAncestor that only works
232 : * for ranges in a Selection. The method will assert and the behavior
233 : * is undefined if called on a range where IsInSelection() is false.
234 : */
235 : nsINode* GetRegisteredCommonAncestor();
236 :
237 : struct NS_STACK_CLASS AutoInvalidateSelection
238 : {
239 : AutoInvalidateSelection(nsRange* aRange) : mRange(aRange)
240 : {
241 : #ifdef DEBUG
242 : mWasInSelection = mRange->IsInSelection();
243 : #endif
244 : if (!mRange->IsInSelection() || mIsNested) {
245 : return;
246 : }
247 : mIsNested = true;
248 : NS_ASSERTION(!mRange->IsDetached(), "detached range in selection");
249 : mCommonAncestor = mRange->GetRegisteredCommonAncestor();
250 : }
251 : ~AutoInvalidateSelection();
252 : nsRange* mRange;
253 : nsRefPtr<nsINode> mCommonAncestor;
254 : #ifdef DEBUG
255 : bool mWasInSelection;
256 : #endif
257 : static bool mIsNested;
258 : };
259 :
260 : nsCOMPtr<nsINode> mRoot;
261 : nsCOMPtr<nsINode> mStartParent;
262 : nsCOMPtr<nsINode> mEndParent;
263 : PRInt32 mStartOffset;
264 : PRInt32 mEndOffset;
265 :
266 : bool mIsPositioned;
267 : bool mIsDetached;
268 : bool mMaySpanAnonymousSubtrees;
269 : bool mInSelection;
270 : };
271 :
272 : #endif /* nsRange_h___ */
|