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 Mozilla.com.
18 : * Portions created by the Initial Developer are Copyright (C) 2006
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Boris Zbarsky <bzbarsky@mit.edu> (Original Author)
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * 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 : #ifndef nsINode_h___
39 : #define nsINode_h___
40 :
41 : #include "nsIDOMEventTarget.h"
42 : #include "nsEvent.h"
43 : #include "nsPropertyTable.h"
44 : #include "nsTObserverArray.h"
45 : #include "nsINodeInfo.h"
46 : #include "nsCOMPtr.h"
47 : #include "nsWrapperCache.h"
48 : #include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT
49 : #include "nsDOMError.h"
50 : #include "nsDOMString.h"
51 : #include "jspubtd.h"
52 : #include "nsWindowMemoryReporter.h"
53 : #include "nsIVariant.h"
54 : #include "nsGkAtoms.h"
55 :
56 : // Including 'windows.h' will #define GetClassInfo to something else.
57 : #ifdef XP_WIN
58 : #ifdef GetClassInfo
59 : #undef GetClassInfo
60 : #endif
61 : #endif
62 :
63 : class nsIContent;
64 : class nsIDocument;
65 : class nsIDOMEvent;
66 : class nsIDOMNode;
67 : class nsIDOMElement;
68 : class nsIDOMNodeList;
69 : class nsINodeList;
70 : class nsIPresShell;
71 : class nsEventChainVisitor;
72 : class nsEventChainPreVisitor;
73 : class nsEventChainPostVisitor;
74 : class nsEventListenerManager;
75 : class nsIPrincipal;
76 : class nsIMutationObserver;
77 : class nsChildContentList;
78 : class nsNodeWeakReference;
79 : class nsNodeSupportsWeakRefTearoff;
80 : class nsIEditor;
81 : class nsIDOMUserDataHandler;
82 : class nsAttrAndChildArray;
83 : class nsXPCClassInfo;
84 :
85 : namespace mozilla {
86 : namespace dom {
87 : class Element;
88 : } // namespace dom
89 : } // namespace mozilla
90 :
91 : enum {
92 : // This bit will be set if the node has a listener manager.
93 : NODE_HAS_LISTENERMANAGER = 0x00000001U,
94 :
95 : // Whether this node has had any properties set on it
96 : NODE_HAS_PROPERTIES = 0x00000002U,
97 :
98 : // Whether this node is the root of an anonymous subtree. Note that this
99 : // need not be a native anonymous subtree. Any anonymous subtree, including
100 : // XBL-generated ones, will do. This flag is set-once: once a node has it,
101 : // it must not be removed.
102 : // NOTE: Should only be used on nsIContent nodes
103 : NODE_IS_ANONYMOUS = 0x00000004U,
104 :
105 : // Whether the node has some ancestor, possibly itself, that is native
106 : // anonymous. This includes ancestors crossing XBL scopes, in cases when an
107 : // XBL binding is attached to an element which has a native anonymous
108 : // ancestor. This flag is set-once: once a node has it, it must not be
109 : // removed.
110 : // NOTE: Should only be used on nsIContent nodes
111 : NODE_IS_IN_ANONYMOUS_SUBTREE = 0x00000008U,
112 :
113 : // Whether this node is the root of a native anonymous (from the perspective
114 : // of its parent) subtree. This flag is set-once: once a node has it, it
115 : // must not be removed.
116 : // NOTE: Should only be used on nsIContent nodes
117 : NODE_IS_NATIVE_ANONYMOUS_ROOT = 0x00000010U,
118 :
119 : // Forces the XBL code to treat this node as if it were
120 : // in the document and therefore should get bindings attached.
121 : NODE_FORCE_XBL_BINDINGS = 0x00000020U,
122 :
123 : // Whether a binding manager may have a pointer to this
124 : NODE_MAY_BE_IN_BINDING_MNGR = 0x00000040U,
125 :
126 : NODE_IS_EDITABLE = 0x00000080U,
127 :
128 : // For all Element nodes, NODE_MAY_HAVE_CLASS is guaranteed to be set if the
129 : // node in fact has a class, but may be set even if it doesn't.
130 : NODE_MAY_HAVE_CLASS = 0x00000100U,
131 :
132 : NODE_IS_INSERTION_PARENT = 0x00000200U,
133 :
134 : // Node has an :empty or :-moz-only-whitespace selector
135 : NODE_HAS_EMPTY_SELECTOR = 0x00000400U,
136 :
137 : // A child of the node has a selector such that any insertion,
138 : // removal, or appending of children requires restyling the parent.
139 : NODE_HAS_SLOW_SELECTOR = 0x00000800U,
140 :
141 : // A child of the node has a :first-child, :-moz-first-node,
142 : // :only-child, :last-child or :-moz-last-node selector.
143 : NODE_HAS_EDGE_CHILD_SELECTOR = 0x00001000U,
144 :
145 : // A child of the node has a selector such that any insertion or
146 : // removal of children requires restyling later siblings of that
147 : // element. Additionally (in this manner it is stronger than
148 : // NODE_HAS_SLOW_SELECTOR), if a child's style changes due to any
149 : // other content tree changes (e.g., the child changes to or from
150 : // matching :empty due to a grandchild insertion or removal), the
151 : // child's later siblings must also be restyled.
152 : NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
153 : = 0x00002000U,
154 :
155 : NODE_ALL_SELECTOR_FLAGS = NODE_HAS_EMPTY_SELECTOR |
156 : NODE_HAS_SLOW_SELECTOR |
157 : NODE_HAS_EDGE_CHILD_SELECTOR |
158 : NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS,
159 :
160 : NODE_ATTACH_BINDING_ON_POSTCREATE
161 : = 0x00004000U,
162 :
163 : // This node needs to go through frame construction to get a frame (or
164 : // undisplayed entry).
165 : NODE_NEEDS_FRAME = 0x00008000U,
166 :
167 : // At least one descendant in the flattened tree has NODE_NEEDS_FRAME set.
168 : // This should be set on every node on the flattened tree path between the
169 : // node(s) with NODE_NEEDS_FRAME and the root content.
170 : NODE_DESCENDANTS_NEED_FRAMES = 0x00010000U,
171 :
172 : // Set if the node has the accesskey attribute set.
173 : NODE_HAS_ACCESSKEY = 0x00020000U,
174 :
175 : // Set if the node is handling a click.
176 : NODE_HANDLING_CLICK = 0x00040000U,
177 :
178 : // Set if the node has had :hover selectors matched against it
179 : NODE_HAS_RELEVANT_HOVER_RULES = 0x00080000U,
180 :
181 : // Two bits for the script-type ID. Not enough to represent all
182 : // nsIProgrammingLanguage values, but we don't care. In practice,
183 : // we can represent the ones we want, and we can fail the others at
184 : // runtime.
185 : NODE_SCRIPT_TYPE_OFFSET = 20,
186 :
187 : NODE_SCRIPT_TYPE_SIZE = 2,
188 :
189 : NODE_SCRIPT_TYPE_MASK = (1 << NODE_SCRIPT_TYPE_SIZE) - 1,
190 :
191 : // Remaining bits are node type specific.
192 : NODE_TYPE_SPECIFIC_BITS_OFFSET =
193 : NODE_SCRIPT_TYPE_OFFSET + NODE_SCRIPT_TYPE_SIZE
194 : };
195 :
196 : PR_STATIC_ASSERT(PRUint32(nsIProgrammingLanguage::JAVASCRIPT) <=
197 : PRUint32(NODE_SCRIPT_TYPE_MASK));
198 : PR_STATIC_ASSERT(PRUint32(nsIProgrammingLanguage::PYTHON) <=
199 : PRUint32(NODE_SCRIPT_TYPE_MASK));
200 :
201 : // Useful inline function for getting a node given an nsIContent and an
202 : // nsIDocument. Returns the first argument cast to nsINode if it is non-null,
203 : // otherwise returns the second (which may be null). We use type variables
204 : // instead of nsIContent* and nsIDocument* because the actual types must be
205 : // known for the cast to work.
206 : template<class C, class D>
207 112066 : inline nsINode* NODE_FROM(C& aContent, D& aDocument)
208 : {
209 112066 : if (aContent)
210 110681 : return static_cast<nsINode*>(aContent);
211 1385 : return static_cast<nsINode*>(aDocument);
212 : }
213 :
214 : /**
215 : * Class used to detect unexpected mutations. To use the class create an
216 : * nsMutationGuard on the stack before unexpected mutations could occur.
217 : * You can then at any time call Mutated to check if any unexpected mutations
218 : * have occurred.
219 : *
220 : * When a guard is instantiated sMutationCount is set to 300. It is then
221 : * decremented by every mutation (capped at 0). This means that we can only
222 : * detect 300 mutations during the lifetime of a single guard, however that
223 : * should be more then we ever care about as we usually only care if more then
224 : * one mutation has occurred.
225 : *
226 : * When the guard goes out of scope it will adjust sMutationCount so that over
227 : * the lifetime of the guard the guard itself has not affected sMutationCount,
228 : * while mutations that happened while the guard was alive still will. This
229 : * allows a guard to be instantiated even if there is another guard higher up
230 : * on the callstack watching for mutations.
231 : *
232 : * The only thing that has to be avoided is for an outer guard to be used
233 : * while an inner guard is alive. This can be avoided by only ever
234 : * instantiating a single guard per scope and only using the guard in the
235 : * current scope.
236 : */
237 : class nsMutationGuard {
238 : public:
239 0 : nsMutationGuard()
240 : {
241 0 : mDelta = eMaxMutations - sMutationCount;
242 0 : sMutationCount = eMaxMutations;
243 0 : }
244 0 : ~nsMutationGuard()
245 : {
246 : sMutationCount =
247 0 : mDelta > sMutationCount ? 0 : sMutationCount - mDelta;
248 0 : }
249 :
250 : /**
251 : * Returns true if any unexpected mutations have occurred. You can pass in
252 : * an 8-bit ignore count to ignore a number of expected mutations.
253 : */
254 0 : bool Mutated(PRUint8 aIgnoreCount)
255 : {
256 0 : return sMutationCount < static_cast<PRUint32>(eMaxMutations - aIgnoreCount);
257 : }
258 :
259 : // This function should be called whenever a mutation that we want to keep
260 : // track of happen. For now this is only done when children are added or
261 : // removed, but we might do it for attribute changes too in the future.
262 123650 : static void DidMutate()
263 : {
264 123650 : if (sMutationCount) {
265 0 : --sMutationCount;
266 : }
267 123650 : }
268 :
269 : private:
270 : // mDelta is the amount sMutationCount was adjusted when the guard was
271 : // initialized. It is needed so that we can undo that adjustment once
272 : // the guard dies.
273 : PRUint32 mDelta;
274 :
275 : // The value 300 is not important, as long as it is bigger then anything
276 : // ever passed to Mutated().
277 : enum { eMaxMutations = 300 };
278 :
279 :
280 : // sMutationCount is a global mutation counter which is decreased by one at
281 : // every mutation. It is capped at 0 to avoid wrapping.
282 : // Its value is always between 0 and 300, inclusive.
283 : static PRUint32 sMutationCount;
284 : };
285 :
286 : // Categories of node properties
287 : // 0 is global.
288 : #define DOM_USER_DATA 1
289 : #define DOM_USER_DATA_HANDLER 2
290 : #define SMIL_MAPPED_ATTR_ANIMVAL 3
291 :
292 : // IID for the nsINode interface
293 : #define NS_INODE_IID \
294 : { 0xfcd3b0d1, 0x75db, 0x46c4, \
295 : { 0xa1, 0xf5, 0x07, 0xc2, 0x09, 0xf8, 0x1f, 0x44 } }
296 :
297 : /**
298 : * An internal interface that abstracts some DOMNode-related parts that both
299 : * nsIContent and nsIDocument share. An instance of this interface has a list
300 : * of nsIContent children and provides access to them.
301 : */
302 : class nsINode : public nsIDOMEventTarget,
303 : public nsWrapperCache
304 : {
305 : public:
306 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID)
307 :
308 : // Among the sub-classes that inherit (directly or indirectly) from nsINode,
309 : // measurement of the following members may be added later if DMD finds it is
310 : // worthwhile:
311 : // - nsGenericHTMLElement: mForm, mFieldSet
312 : // - nsGenericHTMLFrameElement: mFrameLoader (bug 672539), mTitleChangedListener
313 : // - nsHTMLBodyElement: mContentStyleRule
314 : // - nsHTMLDataListElement: mOptions
315 : // - nsHTMLFieldSetElement: mElements, mDependentElements, mFirstLegend
316 : // - nsHTMLFormElement: many!
317 : // - nsHTMLFrameSetElement: mRowSpecs, mColSpecs
318 : // - nsHTMLInputElement: mInputData, mFiles, mFileList, mStaticDocfileList
319 : // - nsHTMLMapElement: mAreas
320 : // - nsHTMLMediaElement: many!
321 : // - nsHTMLOutputElement: mDefaultValue, mTokenList
322 : // - nsHTMLRowElement: mCells
323 : // - nsHTMLSelectElement: mOptions, mRestoreState
324 : // - nsHTMLTableElement: mTBodies, mRows, mTableInheritedAttributes
325 : // - nsHTMLTableSectionElement: mRows
326 : // - nsHTMLTextAreaElement: mControllers, mState
327 : //
328 : // The following members don't need to be measured:
329 : // - nsIContent: mPrimaryFrame, because it's non-owning and measured elsewhere
330 : //
331 : NS_DECL_SIZEOF_EXCLUDING_THIS
332 :
333 : // SizeOfIncludingThis doesn't need to be overridden by sub-classes because
334 : // sub-classes of nsINode are guaranteed to be laid out in memory in such a
335 : // way that |this| points to the start of the allocated object, even in
336 : // methods of nsINode's sub-classes, and so |aMallocSizeOf(this)| is always
337 : // safe to call no matter which object it was invoked on.
338 0 : virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
339 0 : return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
340 : }
341 :
342 : friend class nsNodeUtils;
343 : friend class nsNodeWeakReference;
344 : friend class nsNodeSupportsWeakRefTearoff;
345 : friend class nsAttrAndChildArray;
346 :
347 : #ifdef MOZILLA_INTERNAL_API
348 115287 : nsINode(already_AddRefed<nsINodeInfo> aNodeInfo)
349 : : mNodeInfo(aNodeInfo),
350 : mParent(nsnull),
351 : mFlags(0),
352 : mBoolFlags(0),
353 : mNextSibling(nsnull),
354 : mPreviousSibling(nsnull),
355 : mFirstChild(nsnull),
356 115287 : mSlots(nsnull)
357 : {
358 115287 : }
359 :
360 : #endif
361 :
362 : virtual ~nsINode();
363 :
364 : /**
365 : * Bit-flags to pass (or'ed together) to IsNodeOfType()
366 : */
367 : enum {
368 : /** nsIContent nodes */
369 : eCONTENT = 1 << 0,
370 : /** nsIDocument nodes */
371 : eDOCUMENT = 1 << 1,
372 : /** nsIAttribute nodes */
373 : eATTRIBUTE = 1 << 2,
374 : /** text nodes */
375 : eTEXT = 1 << 3,
376 : /** xml processing instructions */
377 : ePROCESSING_INSTRUCTION = 1 << 4,
378 : /** comment nodes */
379 : eCOMMENT = 1 << 5,
380 : /** form control elements */
381 : eHTML_FORM_CONTROL = 1 << 6,
382 : /** document fragments */
383 : eDOCUMENT_FRAGMENT = 1 << 7,
384 : /** data nodes (comments, PIs, text). Nodes of this type always
385 : returns a non-null value for nsIContent::GetText() */
386 : eDATA_NODE = 1 << 8,
387 : /** nsHTMLMediaElement */
388 : eMEDIA = 1 << 9,
389 : /** animation elements */
390 : eANIMATION = 1 << 10
391 : };
392 :
393 : /**
394 : * API for doing a quick check if a content is of a given
395 : * type, such as Text, Document, Comment ... Use this when you can instead of
396 : * checking the tag.
397 : *
398 : * @param aFlags what types you want to test for (see above)
399 : * @return whether the content matches ALL flags passed in
400 : */
401 : virtual bool IsNodeOfType(PRUint32 aFlags) const = 0;
402 :
403 : /**
404 : * Return whether the node is an Element node
405 : */
406 1211891 : bool IsElement() const {
407 1211891 : return GetBoolFlag(NodeIsElement);
408 : }
409 :
410 : /**
411 : * Return this node as an Element. Should only be used for nodes
412 : * for which IsElement() is true.
413 : */
414 : mozilla::dom::Element* AsElement();
415 :
416 : /**
417 : * Return if this node has any children.
418 : */
419 0 : bool HasChildren() const { return !!mFirstChild; }
420 :
421 : /**
422 : * Get the number of children
423 : * @return the number of children
424 : */
425 : virtual PRUint32 GetChildCount() const = 0;
426 :
427 : /**
428 : * Get a child by index
429 : * @param aIndex the index of the child to get
430 : * @return the child, or null if index out of bounds
431 : */
432 : virtual nsIContent* GetChildAt(PRUint32 aIndex) const = 0;
433 :
434 : /**
435 : * Get a raw pointer to the child array. This should only be used if you
436 : * plan to walk a bunch of the kids, promise to make sure that nothing ever
437 : * mutates (no attribute changes, not DOM tree changes, no script execution,
438 : * NOTHING), and will never ever peform an out-of-bounds access here. This
439 : * method may return null if there are no children, or it may return a
440 : * garbage pointer. In all cases the out param will be set to the number of
441 : * children.
442 : */
443 : virtual nsIContent * const * GetChildArray(PRUint32* aChildCount) const = 0;
444 :
445 : /**
446 : * Get the index of a child within this content
447 : * @param aPossibleChild the child to get the index of.
448 : * @return the index of the child, or -1 if not a child
449 : *
450 : * If the return value is not -1, then calling GetChildAt() with that value
451 : * will return aPossibleChild.
452 : */
453 : virtual PRInt32 IndexOf(nsINode* aPossibleChild) const = 0;
454 :
455 : /**
456 : * Return the "owner document" of this node. Note that this is not the same
457 : * as the DOM ownerDocument -- that's null for Document nodes, whereas for a
458 : * nsIDocument GetOwnerDocument returns the document itself. For nsIContent
459 : * implementations the two are the same.
460 : */
461 1296967 : nsIDocument *OwnerDoc() const
462 : {
463 1296967 : return mNodeInfo->GetDocument();
464 : }
465 :
466 : /**
467 : * Returns true if the content has an ancestor that is a document.
468 : *
469 : * @return whether this content is in a document tree
470 : */
471 1718600 : bool IsInDoc() const
472 : {
473 1718600 : return GetBoolFlag(IsInDocument);
474 : }
475 :
476 : /**
477 : * Get the document that this content is currently in, if any. This will be
478 : * null if the content has no ancestor that is a document.
479 : *
480 : * @return the current document
481 : */
482 1525620 : nsIDocument *GetCurrentDoc() const
483 : {
484 1525620 : return IsInDoc() ? OwnerDoc() : nsnull;
485 : }
486 :
487 : /**
488 : * The values returned by this function are the ones defined for
489 : * nsIDOMNode.nodeType
490 : */
491 937168 : PRUint16 NodeType() const
492 : {
493 937168 : return mNodeInfo->NodeType();
494 : }
495 5894 : const nsString& NodeName() const
496 : {
497 5894 : return mNodeInfo->NodeName();
498 : }
499 8748 : const nsString& LocalName() const
500 : {
501 8748 : return mNodeInfo->LocalName();
502 : }
503 :
504 : nsINode*
505 404 : InsertBefore(nsINode *aNewChild, nsINode *aRefChild, nsresult *aReturn)
506 : {
507 404 : return ReplaceOrInsertBefore(false, aNewChild, aRefChild, aReturn);
508 : }
509 : nsINode*
510 0 : ReplaceChild(nsINode *aNewChild, nsINode *aOldChild, nsresult *aReturn)
511 : {
512 0 : return ReplaceOrInsertBefore(true, aNewChild, aOldChild, aReturn);
513 : }
514 : nsINode*
515 400 : AppendChild(nsINode *aNewChild, nsresult *aReturn)
516 : {
517 400 : return InsertBefore(aNewChild, nsnull, aReturn);
518 : }
519 : nsresult RemoveChild(nsINode *aOldChild);
520 :
521 : /**
522 : * Insert a content node at a particular index. This method handles calling
523 : * BindToTree on the child appropriately.
524 : *
525 : * @param aKid the content to insert
526 : * @param aIndex the index it is being inserted at (the index it will have
527 : * after it is inserted)
528 : * @param aNotify whether to notify the document (current document for
529 : * nsIContent, and |this| for nsIDocument) that the insert has
530 : * occurred
531 : *
532 : * @throws NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have more
533 : * than one element node as a child of a document. Doing this will also
534 : * assert -- you shouldn't be doing it! Check with
535 : * nsIDocument::GetRootElement() first if you're not sure. Apart from this
536 : * one constraint, this doesn't do any checking on whether aKid is a valid
537 : * child of |this|.
538 : *
539 : * @throws NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree).
540 : */
541 : virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
542 : bool aNotify) = 0;
543 :
544 : /**
545 : * Append a content node to the end of the child list. This method handles
546 : * calling BindToTree on the child appropriately.
547 : *
548 : * @param aKid the content to append
549 : * @param aNotify whether to notify the document (current document for
550 : * nsIContent, and |this| for nsIDocument) that the append has
551 : * occurred
552 : *
553 : * @throws NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have more
554 : * than one element node as a child of a document. Doing this will also
555 : * assert -- you shouldn't be doing it! Check with
556 : * nsIDocument::GetRootElement() first if you're not sure. Apart from this
557 : * one constraint, this doesn't do any checking on whether aKid is a valid
558 : * child of |this|.
559 : *
560 : * @throws NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree).
561 : */
562 111536 : nsresult AppendChildTo(nsIContent* aKid, bool aNotify)
563 : {
564 111536 : return InsertChildAt(aKid, GetChildCount(), aNotify);
565 : }
566 :
567 : /**
568 : * Remove a child from this node. This method handles calling UnbindFromTree
569 : * on the child appropriately.
570 : *
571 : * @param aIndex the index of the child to remove
572 : * @param aNotify whether to notify the document (current document for
573 : * nsIContent, and |this| for nsIDocument) that the remove has
574 : * occurred
575 : * @param aMutationEvent whether to fire a mutation event
576 : *
577 : * Note: If there is no child at aIndex, this method will simply do nothing.
578 : */
579 : virtual nsresult RemoveChildAt(PRUint32 aIndex,
580 : bool aNotify) = 0;
581 :
582 : /**
583 : * Get a property associated with this node.
584 : *
585 : * @param aPropertyName name of property to get.
586 : * @param aStatus out parameter for storing resulting status.
587 : * Set to NS_PROPTABLE_PROP_NOT_THERE if the property
588 : * is not set.
589 : * @return the property. Null if the property is not set
590 : * (though a null return value does not imply the
591 : * property was not set, i.e. it can be set to null).
592 : */
593 0 : void* GetProperty(nsIAtom *aPropertyName,
594 : nsresult *aStatus = nsnull) const
595 : {
596 0 : return GetProperty(0, aPropertyName, aStatus);
597 : }
598 :
599 : /**
600 : * Get a property associated with this node.
601 : *
602 : * @param aCategory category of property to get.
603 : * @param aPropertyName name of property to get.
604 : * @param aStatus out parameter for storing resulting status.
605 : * Set to NS_PROPTABLE_PROP_NOT_THERE if the property
606 : * is not set.
607 : * @return the property. Null if the property is not set
608 : * (though a null return value does not imply the
609 : * property was not set, i.e. it can be set to null).
610 : */
611 : virtual void* GetProperty(PRUint16 aCategory,
612 : nsIAtom *aPropertyName,
613 : nsresult *aStatus = nsnull) const;
614 :
615 : /**
616 : * Set a property to be associated with this node. This will overwrite an
617 : * existing value if one exists. The existing value is destroyed using the
618 : * destructor function given when that value was set.
619 : *
620 : * @param aPropertyName name of property to set.
621 : * @param aValue new value of property.
622 : * @param aDtor destructor function to be used when this property
623 : * is destroyed.
624 : * @param aTransfer if true the property will not be deleted when the
625 : * ownerDocument of the node changes, if false it
626 : * will be deleted.
627 : *
628 : * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property
629 : * was already set
630 : * @throws NS_ERROR_OUT_OF_MEMORY if that occurs
631 : */
632 0 : nsresult SetProperty(nsIAtom *aPropertyName,
633 : void *aValue,
634 : NSPropertyDtorFunc aDtor = nsnull,
635 : bool aTransfer = false)
636 : {
637 0 : return SetProperty(0, aPropertyName, aValue, aDtor, aTransfer);
638 : }
639 :
640 : /**
641 : * Set a property to be associated with this node. This will overwrite an
642 : * existing value if one exists. The existing value is destroyed using the
643 : * destructor function given when that value was set.
644 : *
645 : * @param aCategory category of property to set.
646 : * @param aPropertyName name of property to set.
647 : * @param aValue new value of property.
648 : * @param aDtor destructor function to be used when this property
649 : * is destroyed.
650 : * @param aTransfer if true the property will not be deleted when the
651 : * ownerDocument of the node changes, if false it
652 : * will be deleted.
653 : * @param aOldValue [out] previous value of property.
654 : *
655 : * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property
656 : * was already set
657 : * @throws NS_ERROR_OUT_OF_MEMORY if that occurs
658 : */
659 : virtual nsresult SetProperty(PRUint16 aCategory,
660 : nsIAtom *aPropertyName,
661 : void *aValue,
662 : NSPropertyDtorFunc aDtor = nsnull,
663 : bool aTransfer = false,
664 : void **aOldValue = nsnull);
665 :
666 : /**
667 : * Destroys a property associated with this node. The value is destroyed
668 : * using the destruction function given when that value was set.
669 : *
670 : * @param aPropertyName name of property to destroy.
671 : */
672 0 : void DeleteProperty(nsIAtom *aPropertyName)
673 : {
674 0 : DeleteProperty(0, aPropertyName);
675 0 : }
676 :
677 : /**
678 : * Destroys a property associated with this node. The value is destroyed
679 : * using the destruction function given when that value was set.
680 : *
681 : * @param aCategory category of property to destroy.
682 : * @param aPropertyName name of property to destroy.
683 : */
684 : virtual void DeleteProperty(PRUint16 aCategory, nsIAtom *aPropertyName);
685 :
686 : /**
687 : * Unset a property associated with this node. The value will not be
688 : * destroyed but rather returned. It is the caller's responsibility to
689 : * destroy the value after that point.
690 : *
691 : * @param aPropertyName name of property to unset.
692 : * @param aStatus out parameter for storing resulting status.
693 : * Set to NS_PROPTABLE_PROP_NOT_THERE if the property
694 : * is not set.
695 : * @return the property. Null if the property is not set
696 : * (though a null return value does not imply the
697 : * property was not set, i.e. it can be set to null).
698 : */
699 0 : void* UnsetProperty(nsIAtom *aPropertyName,
700 : nsresult *aStatus = nsnull)
701 : {
702 0 : return UnsetProperty(0, aPropertyName, aStatus);
703 : }
704 :
705 : /**
706 : * Unset a property associated with this node. The value will not be
707 : * destroyed but rather returned. It is the caller's responsibility to
708 : * destroy the value after that point.
709 : *
710 : * @param aCategory category of property to unset.
711 : * @param aPropertyName name of property to unset.
712 : * @param aStatus out parameter for storing resulting status.
713 : * Set to NS_PROPTABLE_PROP_NOT_THERE if the property
714 : * is not set.
715 : * @return the property. Null if the property is not set
716 : * (though a null return value does not imply the
717 : * property was not set, i.e. it can be set to null).
718 : */
719 : virtual void* UnsetProperty(PRUint16 aCategory,
720 : nsIAtom *aPropertyName,
721 : nsresult *aStatus = nsnull);
722 :
723 511895 : bool HasProperties() const
724 : {
725 511895 : return HasFlag(NODE_HAS_PROPERTIES);
726 : }
727 :
728 : /**
729 : * Return the principal of this node. This is guaranteed to never be a null
730 : * pointer.
731 : */
732 1383 : nsIPrincipal* NodePrincipal() const {
733 1383 : return mNodeInfo->NodeInfoManager()->DocumentPrincipal();
734 : }
735 :
736 : /**
737 : * Get the parent nsIContent for this node.
738 : * @return the parent, or null if no parent or the parent is not an nsIContent
739 : */
740 878481 : nsIContent* GetParent() const {
741 878481 : return NS_LIKELY(GetBoolFlag(ParentIsContent)) ?
742 878481 : reinterpret_cast<nsIContent*>(mParent) : nsnull;
743 : }
744 :
745 : /**
746 : * Get the parent nsINode for this node. This can be either an nsIContent,
747 : * an nsIDocument or an nsIAttribute.
748 : * @return the parent node
749 : */
750 2769180 : nsINode* GetNodeParent() const
751 : {
752 2769180 : return mParent;
753 : }
754 :
755 : /**
756 : * Get the parent nsINode for this node if it is an Element.
757 : * @return the parent node
758 : */
759 0 : nsINode* GetElementParent() const
760 : {
761 0 : return mParent && mParent->IsElement() ? mParent : nsnull;
762 : }
763 :
764 : /**
765 : * See nsIDOMEventTarget
766 : */
767 : NS_DECL_NSIDOMEVENTTARGET
768 : using nsIDOMEventTarget::AddEventListener;
769 : using nsIDOMEventTarget::AddSystemEventListener;
770 :
771 : /**
772 : * Adds a mutation observer to be notified when this node, or any of its
773 : * descendants, are modified. The node will hold a weak reference to the
774 : * observer, which means that it is the responsibility of the observer to
775 : * remove itself in case it dies before the node. If an observer is added
776 : * while observers are being notified, it may also be notified. In general,
777 : * adding observers while inside a notification is not a good idea. An
778 : * observer that is already observing the node must not be added without
779 : * being removed first.
780 : */
781 5347 : void AddMutationObserver(nsIMutationObserver* aMutationObserver)
782 : {
783 5347 : nsSlots* s = GetSlots();
784 5347 : if (s) {
785 5347 : NS_ASSERTION(s->mMutationObservers.IndexOf(aMutationObserver) ==
786 : nsTArray<int>::NoIndex,
787 : "Observer already in the list");
788 5347 : s->mMutationObservers.AppendElement(aMutationObserver);
789 : }
790 5347 : }
791 :
792 : /**
793 : * Same as above, but only adds the observer if its not observing
794 : * the node already.
795 : */
796 0 : void AddMutationObserverUnlessExists(nsIMutationObserver* aMutationObserver)
797 : {
798 0 : nsSlots* s = GetSlots();
799 0 : if (s) {
800 0 : s->mMutationObservers.AppendElementUnlessExists(aMutationObserver);
801 : }
802 0 : }
803 :
804 : /**
805 : * Removes a mutation observer.
806 : */
807 6426 : void RemoveMutationObserver(nsIMutationObserver* aMutationObserver)
808 : {
809 6426 : nsSlots* s = GetExistingSlots();
810 6426 : if (s) {
811 6426 : s->mMutationObservers.RemoveElement(aMutationObserver);
812 : }
813 6426 : }
814 :
815 : /**
816 : * Clones this node. This needs to be overriden by all node classes. aNodeInfo
817 : * should be identical to this node's nodeInfo, except for the document which
818 : * may be different. When cloning an element, all attributes of the element
819 : * will be cloned. The children of the node will not be cloned.
820 : *
821 : * @param aNodeInfo the nodeinfo to use for the clone
822 : * @param aResult the clone
823 : */
824 : virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const = 0;
825 :
826 : /**
827 : * Checks if a node has the same ownerDocument as this one. Note that this
828 : * actually compares nodeinfo managers because nodes always have one, even
829 : * when they don't have an ownerDocument. If this function returns true
830 : * it doesn't mean that the nodes actually have an ownerDocument.
831 : *
832 : * @param aOther Other node to check
833 : * @return Whether the owner documents of this node and of aOther are the
834 : * same.
835 : */
836 225404 : bool HasSameOwnerDoc(nsINode *aOther)
837 : {
838 : // We compare nodeinfo managers because nodes always have one, even when
839 : // they don't have an ownerDocument.
840 225404 : return mNodeInfo->NodeInfoManager() == aOther->mNodeInfo->NodeInfoManager();
841 : }
842 :
843 : // This class can be extended by subclasses that wish to store more
844 : // information in the slots.
845 : class nsSlots
846 : {
847 : public:
848 4611 : nsSlots()
849 : : mChildNodes(nsnull),
850 4611 : mWeakReference(nsnull)
851 : {
852 4611 : }
853 :
854 : // If needed we could remove the vtable pointer this dtor causes by
855 : // putting a DestroySlots function on nsINode
856 : virtual ~nsSlots();
857 :
858 : void Traverse(nsCycleCollectionTraversalCallback &cb);
859 : void Unlink();
860 :
861 : /**
862 : * A list of mutation observers
863 : */
864 : nsTObserverArray<nsIMutationObserver*> mMutationObservers;
865 :
866 : /**
867 : * An object implementing nsIDOMNodeList for this content (childNodes)
868 : * @see nsIDOMNodeList
869 : * @see nsGenericHTMLElement::GetChildNodes
870 : *
871 : * MSVC 7 doesn't like this as an nsRefPtr
872 : */
873 : nsChildContentList* mChildNodes;
874 :
875 : /**
876 : * Weak reference to this node
877 : */
878 : nsNodeWeakReference* mWeakReference;
879 : };
880 :
881 : /**
882 : * Functions for managing flags and slots
883 : */
884 : #ifdef DEBUG
885 0 : nsSlots* DebugGetSlots()
886 : {
887 0 : return GetSlots();
888 : }
889 : #endif
890 :
891 2687653 : bool HasFlag(PtrBits aFlag) const
892 : {
893 2687653 : return !!(GetFlags() & aFlag);
894 : }
895 :
896 2687653 : PRUint32 GetFlags() const
897 : {
898 2687653 : return mFlags;
899 : }
900 :
901 38038 : void SetFlags(PRUint32 aFlagsToSet)
902 : {
903 38038 : NS_ASSERTION(!(aFlagsToSet & (NODE_IS_ANONYMOUS |
904 : NODE_IS_NATIVE_ANONYMOUS_ROOT |
905 : NODE_IS_IN_ANONYMOUS_SUBTREE |
906 : NODE_ATTACH_BINDING_ON_POSTCREATE |
907 : NODE_DESCENDANTS_NEED_FRAMES |
908 : NODE_NEEDS_FRAME)) ||
909 : IsNodeOfType(eCONTENT),
910 : "Flag only permitted on nsIContent nodes");
911 38038 : mFlags |= aFlagsToSet;
912 38038 : }
913 :
914 708221 : void UnsetFlags(PRUint32 aFlagsToUnset)
915 : {
916 708221 : NS_ASSERTION(!(aFlagsToUnset &
917 : (NODE_IS_ANONYMOUS |
918 : NODE_IS_IN_ANONYMOUS_SUBTREE |
919 : NODE_IS_NATIVE_ANONYMOUS_ROOT)),
920 : "Trying to unset write-only flags");
921 708221 : mFlags &= ~aFlagsToUnset;
922 708221 : }
923 :
924 112044 : void SetEditableFlag(bool aEditable)
925 : {
926 112044 : if (aEditable) {
927 1 : SetFlags(NODE_IS_EDITABLE);
928 : }
929 : else {
930 112043 : UnsetFlags(NODE_IS_EDITABLE);
931 : }
932 112044 : }
933 :
934 49496 : bool IsEditable() const
935 : {
936 : #ifdef _IMPL_NS_LAYOUT
937 49496 : return IsEditableInternal();
938 : #else
939 0 : return IsEditableExternal();
940 : #endif
941 : }
942 :
943 : /**
944 : * Returns true if |this| or any of its ancestors is native anonymous.
945 : */
946 57871 : bool IsInNativeAnonymousSubtree() const
947 : {
948 : #ifdef DEBUG
949 57871 : if (HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE)) {
950 0 : return true;
951 : }
952 57871 : CheckNotNativeAnonymous();
953 57871 : return false;
954 : #else
955 : return HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE);
956 : #endif
957 : }
958 :
959 : /**
960 : * Returns true if |this| node is the common ancestor of the start/end
961 : * nodes of a Range in a Selection or a descendant of such a common ancestor.
962 : * This node is definitely not selected when |false| is returned, but it may
963 : * or may not be selected when |true| is returned.
964 : */
965 18 : bool IsSelectionDescendant() const
966 : {
967 18 : return IsDescendantOfCommonAncestorForRangeInSelection() ||
968 18 : IsCommonAncestorForRangeInSelection();
969 : }
970 :
971 : /**
972 : * Get the root content of an editor. So, this node must be a descendant of
973 : * an editor. Note that this should be only used for getting input or textarea
974 : * editor's root content. This method doesn't support HTML editors.
975 : */
976 : nsIContent* GetTextEditorRootContent(nsIEditor** aEditor = nsnull);
977 :
978 : /**
979 : * Get the nearest selection root, ie. the node that will be selected if the
980 : * user does "Select All" while the focus is in this node. Note that if this
981 : * node is not in an editor, the result comes from the nsFrameSelection that
982 : * is related to aPresShell, so the result might not be the ancestor of this
983 : * node. Be aware that if this node and the computed selection limiter are
984 : * not in same subtree, this returns the root content of the closeset subtree.
985 : */
986 : nsIContent* GetSelectionRootContent(nsIPresShell* aPresShell);
987 :
988 : virtual nsINodeList* GetChildNodesList();
989 491565 : nsIContent* GetFirstChild() const { return mFirstChild; }
990 359 : nsIContent* GetLastChild() const
991 : {
992 : PRUint32 count;
993 359 : nsIContent* const* children = GetChildArray(&count);
994 :
995 359 : return count > 0 ? children[count - 1] : nsnull;
996 : }
997 :
998 : /**
999 : * Implementation is in nsIDocument.h, because it needs to cast from
1000 : * nsIDocument* to nsINode*.
1001 : */
1002 : nsIDocument* GetOwnerDocument() const;
1003 :
1004 : /**
1005 : * The default script type (language) ID for this node.
1006 : * All nodes must support fetching the default script language.
1007 : */
1008 0 : virtual PRUint32 GetScriptTypeID() const
1009 0 : { return nsIProgrammingLanguage::JAVASCRIPT; }
1010 :
1011 : /**
1012 : * Not all nodes support setting a new default language.
1013 : */
1014 0 : NS_IMETHOD SetScriptTypeID(PRUint32 aLang)
1015 : {
1016 0 : NS_NOTREACHED("SetScriptTypeID not implemented");
1017 0 : return NS_ERROR_NOT_IMPLEMENTED;
1018 : }
1019 :
1020 : nsresult Normalize();
1021 :
1022 : /**
1023 : * Get the base URI for any relative URIs within this piece of
1024 : * content. Generally, this is the document's base URI, but certain
1025 : * content carries a local base for backward compatibility, and XML
1026 : * supports setting a per-node base URI.
1027 : *
1028 : * @return the base URI
1029 : */
1030 : virtual already_AddRefed<nsIURI> GetBaseURI() const = 0;
1031 :
1032 : /**
1033 : * Facility for explicitly setting a base URI on a node.
1034 : */
1035 : nsresult SetExplicitBaseURI(nsIURI* aURI);
1036 : /**
1037 : * The explicit base URI, if set, otherwise null
1038 : */
1039 : protected:
1040 0 : nsIURI* GetExplicitBaseURI() const {
1041 0 : if (HasExplicitBaseURI()) {
1042 0 : return static_cast<nsIURI*>(GetProperty(nsGkAtoms::baseURIProperty));
1043 : }
1044 0 : return nsnull;
1045 : }
1046 :
1047 : public:
1048 : nsresult GetDOMBaseURI(nsAString &aURI) const;
1049 :
1050 : // Note! This function must never fail. It only return an nsresult so that
1051 : // we can use it to implement nsIDOMNode
1052 0 : NS_IMETHOD GetTextContent(nsAString &aTextContent)
1053 : {
1054 0 : SetDOMStringToNull(aTextContent);
1055 0 : return NS_OK;
1056 : }
1057 0 : NS_IMETHOD SetTextContent(const nsAString& aTextContent)
1058 : {
1059 0 : return NS_OK;
1060 : }
1061 :
1062 : /**
1063 : * Associate an object aData to aKey on this node. If aData is null any
1064 : * previously registered object and UserDataHandler associated to aKey on
1065 : * this node will be removed.
1066 : * Should only be used to implement the DOM Level 3 UserData API.
1067 : *
1068 : * @param aKey the key to associate the object to
1069 : * @param aData the object to associate to aKey on this node (may be null)
1070 : * @param aHandler the UserDataHandler to call when the node is
1071 : * cloned/deleted/imported/renamed (may be null)
1072 : * @param aResult [out] the previously registered object for aKey on this
1073 : * node, if any
1074 : * @return whether adding the object and UserDataHandler succeeded
1075 : */
1076 : nsresult SetUserData(const nsAString& aKey, nsIVariant* aData,
1077 : nsIDOMUserDataHandler* aHandler, nsIVariant** aResult);
1078 :
1079 : /**
1080 : * Get the UserData object registered for a Key on this node, if any.
1081 : * Should only be used to implement the DOM Level 3 UserData API.
1082 : *
1083 : * @param aKey the key to get UserData for
1084 : * @return aResult the previously registered object for aKey on this node, if
1085 : * any
1086 : */
1087 0 : nsIVariant* GetUserData(const nsAString& aKey)
1088 : {
1089 0 : nsCOMPtr<nsIAtom> key = do_GetAtom(aKey);
1090 0 : if (!key) {
1091 0 : return nsnull;
1092 : }
1093 :
1094 0 : return static_cast<nsIVariant*>(GetProperty(DOM_USER_DATA, key));
1095 : }
1096 :
1097 0 : nsresult GetUserData(const nsAString& aKey, nsIVariant** aResult)
1098 : {
1099 0 : NS_IF_ADDREF(*aResult = GetUserData(aKey));
1100 :
1101 0 : return NS_OK;
1102 : }
1103 :
1104 :
1105 : /**
1106 : * Compares the document position of a node to this node.
1107 : *
1108 : * @param aOtherNode The node whose position is being compared to this node
1109 : *
1110 : * @return The document position flags of the nodes. aOtherNode is compared
1111 : * to this node, i.e. if aOtherNode is before this node then
1112 : * DOCUMENT_POSITION_PRECEDING will be set.
1113 : *
1114 : * @see nsIDOMNode
1115 : */
1116 : PRUint16 CompareDocPosition(nsINode* aOtherNode);
1117 0 : nsresult CompareDocPosition(nsINode* aOtherNode, PRUint16* aReturn)
1118 : {
1119 0 : NS_ENSURE_ARG(aOtherNode);
1120 0 : *aReturn = CompareDocPosition(aOtherNode);
1121 0 : return NS_OK;
1122 : }
1123 : nsresult CompareDocumentPosition(nsIDOMNode* aOther,
1124 : PRUint16* aReturn);
1125 :
1126 : nsresult LookupPrefix(const nsAString& aNamespaceURI, nsAString& aPrefix);
1127 0 : nsresult IsDefaultNamespace(const nsAString& aNamespaceURI, bool* aResult)
1128 : {
1129 0 : nsAutoString defaultNamespace;
1130 0 : LookupNamespaceURI(EmptyString(), defaultNamespace);
1131 0 : *aResult = aNamespaceURI.Equals(defaultNamespace);
1132 0 : return NS_OK;
1133 : }
1134 : nsresult LookupNamespaceURI(const nsAString& aNamespacePrefix,
1135 : nsAString& aNamespaceURI);
1136 :
1137 : nsresult IsEqualNode(nsIDOMNode* aOther, bool* aReturn);
1138 : bool IsEqualTo(nsINode* aOther);
1139 :
1140 567397 : nsIContent* GetNextSibling() const { return mNextSibling; }
1141 112205 : nsIContent* GetPreviousSibling() const { return mPreviousSibling; }
1142 :
1143 : /**
1144 : * Get the next node in the pre-order tree traversal of the DOM. If
1145 : * aRoot is non-null, then it must be an ancestor of |this|
1146 : * (possibly equal to |this|) and only nodes that are descendants of
1147 : * aRoot, not including aRoot itself, will be returned. Returns
1148 : * null if there are no more nodes to traverse.
1149 : */
1150 433674 : nsIContent* GetNextNode(const nsINode* aRoot = nsnull) const
1151 : {
1152 433674 : return GetNextNodeImpl(aRoot, false);
1153 : }
1154 :
1155 : /**
1156 : * Get the next node in the pre-order tree traversal of the DOM but ignoring
1157 : * the children of this node. If aRoot is non-null, then it must be an
1158 : * ancestor of |this| (possibly equal to |this|) and only nodes that are
1159 : * descendants of aRoot, not including aRoot itself, will be returned.
1160 : * Returns null if there are no more nodes to traverse.
1161 : */
1162 2 : nsIContent* GetNextNonChildNode(const nsINode* aRoot = nsnull) const
1163 : {
1164 2 : return GetNextNodeImpl(aRoot, true);
1165 : }
1166 :
1167 : /**
1168 : * Returns true if 'this' is either document or element or
1169 : * document fragment and aOther is a descendant in the same
1170 : * anonymous tree.
1171 : */
1172 : bool Contains(const nsINode* aOther) const;
1173 : nsresult Contains(nsIDOMNode* aOther, bool* aReturn);
1174 :
1175 : private:
1176 :
1177 433676 : nsIContent* GetNextNodeImpl(const nsINode* aRoot,
1178 : const bool aSkipChildren) const
1179 : {
1180 : // Can't use nsContentUtils::ContentIsDescendantOf here, since we
1181 : // can't include it here.
1182 : #ifdef DEBUG
1183 433676 : if (aRoot) {
1184 433676 : const nsINode* cur = this;
1185 2761306 : for (; cur; cur = cur->GetNodeParent())
1186 2761306 : if (cur == aRoot) break;
1187 433676 : NS_ASSERTION(cur, "aRoot not an ancestor of |this|?");
1188 : }
1189 : #endif
1190 433676 : if (!aSkipChildren) {
1191 433674 : nsIContent* kid = GetFirstChild();
1192 433674 : if (kid) {
1193 140813 : return kid;
1194 : }
1195 : }
1196 292863 : if (this == aRoot) {
1197 12 : return nsnull;
1198 : }
1199 292851 : const nsINode* cur = this;
1200 137599 : while (1) {
1201 430450 : nsIContent* next = cur->GetNextSibling();
1202 430450 : if (next) {
1203 287613 : return next;
1204 : }
1205 142837 : nsINode* parent = cur->GetNodeParent();
1206 142837 : if (parent == aRoot) {
1207 5238 : return nsnull;
1208 : }
1209 137599 : cur = parent;
1210 : }
1211 : NS_NOTREACHED("How did we get here?");
1212 : }
1213 :
1214 : public:
1215 :
1216 : /**
1217 : * Get the previous nsIContent in the pre-order tree traversal of the DOM. If
1218 : * aRoot is non-null, then it must be an ancestor of |this|
1219 : * (possibly equal to |this|) and only nsIContents that are descendants of
1220 : * aRoot, including aRoot itself, will be returned. Returns
1221 : * null if there are no more nsIContents to traverse.
1222 : */
1223 0 : nsIContent* GetPreviousContent(const nsINode* aRoot = nsnull) const
1224 : {
1225 : // Can't use nsContentUtils::ContentIsDescendantOf here, since we
1226 : // can't include it here.
1227 : #ifdef DEBUG
1228 0 : if (aRoot) {
1229 0 : const nsINode* cur = this;
1230 0 : for (; cur; cur = cur->GetNodeParent())
1231 0 : if (cur == aRoot) break;
1232 0 : NS_ASSERTION(cur, "aRoot not an ancestor of |this|?");
1233 : }
1234 : #endif
1235 :
1236 0 : if (this == aRoot) {
1237 0 : return nsnull;
1238 : }
1239 0 : nsIContent* cur = this->GetParent();
1240 0 : nsIContent* iter = this->GetPreviousSibling();
1241 0 : while (iter) {
1242 0 : cur = iter;
1243 0 : iter = reinterpret_cast<nsINode*>(iter)->GetLastChild();
1244 : }
1245 0 : return cur;
1246 : }
1247 :
1248 : /**
1249 : * Boolean flags
1250 : */
1251 : private:
1252 : enum BooleanFlag {
1253 : // Set if we're being used from -moz-element
1254 : NodeHasRenderingObservers,
1255 : // Set if our parent chain (including this node itself) terminates
1256 : // in a document
1257 : IsInDocument,
1258 : // Set if mParent is an nsIContent
1259 : ParentIsContent,
1260 : // Set if this node is an Element
1261 : NodeIsElement,
1262 : // Set if the element has a non-empty id attribute. This can in rare
1263 : // cases lie for nsXMLElement, such as when the node has been moved between
1264 : // documents with different id mappings.
1265 : ElementHasID,
1266 : // Set if the element might have inline style.
1267 : ElementMayHaveStyle,
1268 : // Set if the element has a name attribute set.
1269 : ElementHasName,
1270 : // Set if the element might have a contenteditable attribute set.
1271 : ElementMayHaveContentEditableAttr,
1272 : // Set if the node is the common ancestor of the start/end nodes of a Range
1273 : // that is in a Selection.
1274 : NodeIsCommonAncestorForRangeInSelection,
1275 : // Set if the node is a descendant of a node with the above bit set.
1276 : NodeIsDescendantOfCommonAncestorForRangeInSelection,
1277 : // Set if CanSkipInCC check has been done for this subtree root.
1278 : NodeIsCCMarkedRoot,
1279 : // Maybe set if this node is in black subtree.
1280 : NodeIsCCBlackTree,
1281 : // Maybe set if the node is a root of a subtree
1282 : // which needs to be kept in the purple buffer.
1283 : NodeIsPurpleRoot,
1284 : // Set if the node has an explicit base URI stored
1285 : NodeHasExplicitBaseURI,
1286 : // Set if the element has some style states locked
1287 : ElementHasLockedStyleStates,
1288 : // Guard value
1289 : BooleanFlagCount
1290 : };
1291 :
1292 230117 : void SetBoolFlag(BooleanFlag name, bool value) {
1293 : PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
1294 230117 : mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
1295 230117 : }
1296 :
1297 150814 : void SetBoolFlag(BooleanFlag name) {
1298 : PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
1299 150814 : mBoolFlags |= (1 << name);
1300 150814 : }
1301 :
1302 370643 : void ClearBoolFlag(BooleanFlag name) {
1303 : PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
1304 370643 : mBoolFlags &= ~(1 << name);
1305 370643 : }
1306 :
1307 4442666 : bool GetBoolFlag(BooleanFlag name) const {
1308 : PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
1309 4442666 : return mBoolFlags & (1 << name);
1310 : }
1311 :
1312 : public:
1313 0 : bool HasRenderingObservers() const
1314 0 : { return GetBoolFlag(NodeHasRenderingObservers); }
1315 0 : void SetHasRenderingObservers(bool aValue)
1316 0 : { SetBoolFlag(NodeHasRenderingObservers, aValue); }
1317 157261 : bool HasID() const { return GetBoolFlag(ElementHasID); }
1318 790 : bool MayHaveStyle() const { return GetBoolFlag(ElementMayHaveStyle); }
1319 2038 : bool HasName() const { return GetBoolFlag(ElementHasName); }
1320 2040 : bool MayHaveContentEditableAttr() const
1321 2040 : { return GetBoolFlag(ElementMayHaveContentEditableAttr); }
1322 18 : bool IsCommonAncestorForRangeInSelection() const
1323 18 : { return GetBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
1324 0 : void SetCommonAncestorForRangeInSelection()
1325 0 : { SetBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
1326 0 : void ClearCommonAncestorForRangeInSelection()
1327 0 : { ClearBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
1328 18 : bool IsDescendantOfCommonAncestorForRangeInSelection() const
1329 18 : { return GetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
1330 0 : void SetDescendantOfCommonAncestorForRangeInSelection()
1331 0 : { SetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
1332 0 : void ClearDescendantOfCommonAncestorForRangeInSelection()
1333 0 : { ClearBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
1334 :
1335 402 : void SetCCMarkedRoot(bool aValue)
1336 402 : { SetBoolFlag(NodeIsCCMarkedRoot, aValue); }
1337 26226 : bool CCMarkedRoot() const { return GetBoolFlag(NodeIsCCMarkedRoot); }
1338 402 : void SetInCCBlackTree(bool aValue)
1339 402 : { SetBoolFlag(NodeIsCCBlackTree, aValue); }
1340 148084 : bool InCCBlackTree() const { return GetBoolFlag(NodeIsCCBlackTree); }
1341 4332 : void SetIsPurpleRoot(bool aValue)
1342 4332 : { SetBoolFlag(NodeIsPurpleRoot, aValue); }
1343 297219 : bool IsPurpleRoot() const { return GetBoolFlag(NodeIsPurpleRoot); }
1344 :
1345 36614 : bool HasListenerManager() { return HasFlag(NODE_HAS_LISTENERMANAGER); }
1346 : protected:
1347 224981 : void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
1348 112579 : void SetInDocument() { SetBoolFlag(IsInDocument); }
1349 370575 : void ClearInDocument() { ClearBoolFlag(IsInDocument); }
1350 38033 : void SetIsElement() { SetBoolFlag(NodeIsElement); }
1351 68 : void ClearIsElement() { ClearBoolFlag(NodeIsElement); }
1352 202 : void SetHasID() { SetBoolFlag(ElementHasID); }
1353 0 : void ClearHasID() { ClearBoolFlag(ElementHasID); }
1354 0 : void SetMayHaveStyle() { SetBoolFlag(ElementMayHaveStyle); }
1355 0 : void SetHasName() { SetBoolFlag(ElementHasName); }
1356 0 : void ClearHasName() { ClearBoolFlag(ElementHasName); }
1357 0 : void SetMayHaveContentEditableAttr()
1358 0 : { SetBoolFlag(ElementMayHaveContentEditableAttr); }
1359 0 : bool HasExplicitBaseURI() const { return GetBoolFlag(NodeHasExplicitBaseURI); }
1360 0 : void SetHasExplicitBaseURI() { SetBoolFlag(NodeHasExplicitBaseURI); }
1361 0 : void SetHasLockedStyleStates() { SetBoolFlag(ElementHasLockedStyleStates); }
1362 0 : void ClearHasLockedStyleStates() { ClearBoolFlag(ElementHasLockedStyleStates); }
1363 0 : bool HasLockedStyleStates() const
1364 0 : { return GetBoolFlag(ElementHasLockedStyleStates); }
1365 :
1366 : public:
1367 : // Optimized way to get classinfo.
1368 : virtual nsXPCClassInfo* GetClassInfo() = 0;
1369 :
1370 : protected:
1371 :
1372 : // Override this function to create a custom slots class.
1373 : virtual nsINode::nsSlots* CreateSlots();
1374 :
1375 133257 : bool HasSlots() const
1376 : {
1377 133257 : return mSlots != nsnull;
1378 : }
1379 :
1380 1729510 : nsSlots* GetExistingSlots() const
1381 : {
1382 1729510 : return mSlots;
1383 : }
1384 :
1385 17976 : nsSlots* GetSlots()
1386 : {
1387 17976 : if (!HasSlots()) {
1388 4611 : mSlots = CreateSlots();
1389 : }
1390 17976 : return GetExistingSlots();
1391 : }
1392 :
1393 0 : nsTObserverArray<nsIMutationObserver*> *GetMutationObservers()
1394 : {
1395 0 : return HasSlots() ? &GetExistingSlots()->mMutationObservers : nsnull;
1396 : }
1397 :
1398 : bool IsEditableInternal() const;
1399 0 : virtual bool IsEditableExternal() const
1400 : {
1401 0 : return IsEditableInternal();
1402 : }
1403 :
1404 : #ifdef DEBUG
1405 : // Note: virtual so that IsInNativeAnonymousSubtree can be called accross
1406 : // module boundaries.
1407 : virtual void CheckNotNativeAnonymous() const;
1408 : #endif
1409 :
1410 : nsresult GetParentNode(nsIDOMNode** aParentNode);
1411 : nsresult GetParentElement(nsIDOMElement** aParentElement);
1412 : nsresult GetChildNodes(nsIDOMNodeList** aChildNodes);
1413 : nsresult GetFirstChild(nsIDOMNode** aFirstChild);
1414 : nsresult GetLastChild(nsIDOMNode** aLastChild);
1415 : nsresult GetPreviousSibling(nsIDOMNode** aPrevSibling);
1416 : nsresult GetNextSibling(nsIDOMNode** aNextSibling);
1417 : nsresult GetOwnerDocument(nsIDOMDocument** aOwnerDocument);
1418 :
1419 : nsresult ReplaceOrInsertBefore(bool aReplace, nsIDOMNode *aNewChild,
1420 : nsIDOMNode *aRefChild, nsIDOMNode **aReturn);
1421 404 : nsINode* ReplaceOrInsertBefore(bool aReplace, nsINode *aNewChild,
1422 : nsINode *aRefChild, nsresult *aReturn)
1423 : {
1424 404 : *aReturn = ReplaceOrInsertBefore(aReplace, aNewChild, aRefChild);
1425 404 : if (NS_FAILED(*aReturn)) {
1426 0 : return nsnull;
1427 : }
1428 :
1429 404 : return aReplace ? aRefChild : aNewChild;
1430 : }
1431 : virtual nsresult ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
1432 : nsINode* aRefChild);
1433 : nsresult RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn);
1434 :
1435 : /**
1436 : * Returns the Element that should be used for resolving namespaces
1437 : * on this node (ie the ownerElement for attributes, the documentElement for
1438 : * documents, the node itself for elements and for other nodes the parentNode
1439 : * if it is an element).
1440 : */
1441 : virtual mozilla::dom::Element* GetNameSpaceElement() = 0;
1442 :
1443 : /**
1444 : * Most of the implementation of the nsINode RemoveChildAt method.
1445 : * Should only be called on document, element, and document fragment
1446 : * nodes. The aChildArray passed in should be the one for |this|.
1447 : *
1448 : * @param aIndex The index to remove at.
1449 : * @param aNotify Whether to notify.
1450 : * @param aKid The kid at aIndex. Must not be null.
1451 : * @param aChildArray The child array to work with.
1452 : * @param aMutationEvent whether to fire a mutation event for this removal.
1453 : */
1454 : nsresult doRemoveChildAt(PRUint32 aIndex, bool aNotify, nsIContent* aKid,
1455 : nsAttrAndChildArray& aChildArray);
1456 :
1457 : /**
1458 : * Most of the implementation of the nsINode InsertChildAt method.
1459 : * Should only be called on document, element, and document fragment
1460 : * nodes. The aChildArray passed in should be the one for |this|.
1461 : *
1462 : * @param aKid The child to insert.
1463 : * @param aIndex The index to insert at.
1464 : * @param aNotify Whether to notify.
1465 : * @param aChildArray The child array to work with
1466 : */
1467 : nsresult doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
1468 : bool aNotify, nsAttrAndChildArray& aChildArray);
1469 :
1470 : public:
1471 : /* Event stuff that documents and elements share. This needs to be
1472 : NS_IMETHOD because some subclasses implement DOM methods with
1473 : this exact name and signature and then the calling convention
1474 : needs to match.
1475 :
1476 : Note that we include DOCUMENT_ONLY_EVENT events here so that we
1477 : can forward all the document stuff to this implementation.
1478 : */
1479 : #define EVENT(name_, id_, type_, struct_) \
1480 : NS_IMETHOD GetOn##name_(JSContext *cx, JS::Value *vp); \
1481 : NS_IMETHOD SetOn##name_(JSContext *cx, const JS::Value &v);
1482 : #define TOUCH_EVENT EVENT
1483 : #define DOCUMENT_ONLY_EVENT EVENT
1484 : #include "nsEventNameList.h"
1485 : #undef DOCUMENT_ONLY_EVENT
1486 : #undef TOUCH_EVENT
1487 : #undef EVENT
1488 :
1489 : protected:
1490 : static void Trace(nsINode *tmp, TraceCallback cb, void *closure);
1491 : static bool Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb);
1492 : static void Unlink(nsINode *tmp);
1493 :
1494 : nsCOMPtr<nsINodeInfo> mNodeInfo;
1495 :
1496 : nsINode* mParent;
1497 :
1498 : PRUint32 mFlags;
1499 :
1500 : private:
1501 : // Boolean flags.
1502 : PRUint32 mBoolFlags;
1503 :
1504 : protected:
1505 : nsIContent* mNextSibling;
1506 : nsIContent* mPreviousSibling;
1507 : nsIContent* mFirstChild;
1508 :
1509 : // Storage for more members that are usually not needed; allocated lazily.
1510 : nsSlots* mSlots;
1511 : };
1512 :
1513 :
1514 : extern const nsIID kThisPtrOffsetsSID;
1515 :
1516 : // _implClass is the class to use to cast to nsISupports
1517 : #define NS_OFFSET_AND_INTERFACE_TABLE_BEGIN_AMBIGUOUS(_class, _implClass) \
1518 : static const QITableEntry offsetAndQITable[] = { \
1519 : NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsISupports, _implClass)
1520 :
1521 : #define NS_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
1522 : NS_OFFSET_AND_INTERFACE_TABLE_BEGIN_AMBIGUOUS(_class, _class)
1523 :
1524 : #define NS_OFFSET_AND_INTERFACE_TABLE_END \
1525 : { nsnull, 0 } }; \
1526 : if (aIID.Equals(kThisPtrOffsetsSID)) { \
1527 : *aInstancePtr = \
1528 : const_cast<void*>(static_cast<const void*>(&offsetAndQITable)); \
1529 : return NS_OK; \
1530 : }
1531 :
1532 : #define NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE \
1533 : rv = NS_TableDrivenQI(this, offsetAndQITable, aIID, aInstancePtr); \
1534 : NS_INTERFACE_TABLE_TO_MAP_SEGUE
1535 :
1536 : // nsNodeSH::PreCreate() depends on the identity pointer being the same as
1537 : // nsINode, so if you change the nsISupports line below, make sure
1538 : // nsNodeSH::PreCreate() still does the right thing!
1539 : #define NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
1540 : NS_OFFSET_AND_INTERFACE_TABLE_BEGIN_AMBIGUOUS(_class, nsINode) \
1541 : NS_INTERFACE_TABLE_ENTRY(_class, nsINode)
1542 :
1543 : #define NS_NODE_INTERFACE_TABLE2(_class, _i1, _i2) \
1544 : NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
1545 : NS_INTERFACE_TABLE_ENTRY(_class, _i1) \
1546 : NS_INTERFACE_TABLE_ENTRY(_class, _i2) \
1547 : NS_OFFSET_AND_INTERFACE_TABLE_END \
1548 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1549 :
1550 : #define NS_NODE_INTERFACE_TABLE3(_class, _i1, _i2, _i3) \
1551 : NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
1552 : NS_INTERFACE_TABLE_ENTRY(_class, _i1) \
1553 : NS_INTERFACE_TABLE_ENTRY(_class, _i2) \
1554 : NS_INTERFACE_TABLE_ENTRY(_class, _i3) \
1555 : NS_OFFSET_AND_INTERFACE_TABLE_END \
1556 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1557 :
1558 : #define NS_NODE_INTERFACE_TABLE4(_class, _i1, _i2, _i3, _i4) \
1559 : NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
1560 : NS_INTERFACE_TABLE_ENTRY(_class, _i1) \
1561 : NS_INTERFACE_TABLE_ENTRY(_class, _i2) \
1562 : NS_INTERFACE_TABLE_ENTRY(_class, _i3) \
1563 : NS_INTERFACE_TABLE_ENTRY(_class, _i4) \
1564 : NS_OFFSET_AND_INTERFACE_TABLE_END \
1565 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1566 :
1567 : #define NS_NODE_INTERFACE_TABLE5(_class, _i1, _i2, _i3, _i4, _i5) \
1568 : NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
1569 : NS_INTERFACE_TABLE_ENTRY(_class, _i1) \
1570 : NS_INTERFACE_TABLE_ENTRY(_class, _i2) \
1571 : NS_INTERFACE_TABLE_ENTRY(_class, _i3) \
1572 : NS_INTERFACE_TABLE_ENTRY(_class, _i4) \
1573 : NS_INTERFACE_TABLE_ENTRY(_class, _i5) \
1574 : NS_OFFSET_AND_INTERFACE_TABLE_END \
1575 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1576 :
1577 : #define NS_NODE_INTERFACE_TABLE6(_class, _i1, _i2, _i3, _i4, _i5, _i6) \
1578 : NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
1579 : NS_INTERFACE_TABLE_ENTRY(_class, _i1) \
1580 : NS_INTERFACE_TABLE_ENTRY(_class, _i2) \
1581 : NS_INTERFACE_TABLE_ENTRY(_class, _i3) \
1582 : NS_INTERFACE_TABLE_ENTRY(_class, _i4) \
1583 : NS_INTERFACE_TABLE_ENTRY(_class, _i5) \
1584 : NS_INTERFACE_TABLE_ENTRY(_class, _i6) \
1585 : NS_OFFSET_AND_INTERFACE_TABLE_END \
1586 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1587 :
1588 : #define NS_NODE_INTERFACE_TABLE7(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) \
1589 : NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
1590 : NS_INTERFACE_TABLE_ENTRY(_class, _i1) \
1591 : NS_INTERFACE_TABLE_ENTRY(_class, _i2) \
1592 : NS_INTERFACE_TABLE_ENTRY(_class, _i3) \
1593 : NS_INTERFACE_TABLE_ENTRY(_class, _i4) \
1594 : NS_INTERFACE_TABLE_ENTRY(_class, _i5) \
1595 : NS_INTERFACE_TABLE_ENTRY(_class, _i6) \
1596 : NS_INTERFACE_TABLE_ENTRY(_class, _i7) \
1597 : NS_OFFSET_AND_INTERFACE_TABLE_END \
1598 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1599 :
1600 : #define NS_NODE_INTERFACE_TABLE8(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \
1601 : _i8) \
1602 : NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
1603 : NS_INTERFACE_TABLE_ENTRY(_class, _i1) \
1604 : NS_INTERFACE_TABLE_ENTRY(_class, _i2) \
1605 : NS_INTERFACE_TABLE_ENTRY(_class, _i3) \
1606 : NS_INTERFACE_TABLE_ENTRY(_class, _i4) \
1607 : NS_INTERFACE_TABLE_ENTRY(_class, _i5) \
1608 : NS_INTERFACE_TABLE_ENTRY(_class, _i6) \
1609 : NS_INTERFACE_TABLE_ENTRY(_class, _i7) \
1610 : NS_INTERFACE_TABLE_ENTRY(_class, _i8) \
1611 : NS_OFFSET_AND_INTERFACE_TABLE_END \
1612 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1613 :
1614 :
1615 : NS_DEFINE_STATIC_IID_ACCESSOR(nsINode, NS_INODE_IID)
1616 :
1617 :
1618 : #define NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER \
1619 : nsContentUtils::TraceWrapper(tmp, aCallback, aClosure);
1620 :
1621 : #define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
1622 : nsContentUtils::ReleaseWrapper(s, tmp);
1623 :
1624 :
1625 : #endif /* nsINode_h___ */
|