1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 sw=2 et tw=79: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Ms2ger <ms2ger@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /*
41 : * Base class for all element classes; this provides an implementation
42 : * of DOM Core's nsIDOMElement, implements nsIContent, provides
43 : * utility methods for subclasses, and so forth.
44 : */
45 :
46 : #include "mozilla/Util.h"
47 :
48 : #include "nsGenericElement.h"
49 :
50 : #include "nsDOMAttribute.h"
51 : #include "nsDOMAttributeMap.h"
52 : #include "nsIAtom.h"
53 : #include "nsINodeInfo.h"
54 : #include "nsIDocument.h"
55 : #include "nsIDOMNodeList.h"
56 : #include "nsIDOMDocument.h"
57 : #include "nsIContentIterator.h"
58 : #include "nsEventListenerManager.h"
59 : #include "nsFocusManager.h"
60 : #include "nsILinkHandler.h"
61 : #include "nsIScriptGlobalObject.h"
62 : #include "nsIURL.h"
63 : #include "nsNetUtil.h"
64 : #include "nsIFrame.h"
65 : #include "nsIAnonymousContentCreator.h"
66 : #include "nsIPresShell.h"
67 : #include "nsPresContext.h"
68 : #include "nsStyleConsts.h"
69 : #include "nsString.h"
70 : #include "nsUnicharUtils.h"
71 : #include "nsEventStateManager.h"
72 : #include "nsIDOMEvent.h"
73 : #include "nsIPrivateDOMEvent.h"
74 : #include "nsDOMCID.h"
75 : #include "nsIServiceManager.h"
76 : #include "nsIDOMCSSStyleDeclaration.h"
77 : #include "nsDOMCSSAttrDeclaration.h"
78 : #include "nsINameSpaceManager.h"
79 : #include "nsContentList.h"
80 : #include "nsDOMTokenList.h"
81 : #include "nsXBLPrototypeBinding.h"
82 : #include "nsDOMError.h"
83 : #include "nsDOMString.h"
84 : #include "nsIScriptSecurityManager.h"
85 : #include "nsIDOMMutationEvent.h"
86 : #include "nsMutationEvent.h"
87 : #include "nsNodeUtils.h"
88 : #include "nsDocument.h"
89 : #include "nsAttrValueOrString.h"
90 : #ifdef MOZ_XUL
91 : #include "nsXULElement.h"
92 : #endif /* MOZ_XUL */
93 : #include "nsFrameManager.h"
94 : #include "nsFrameSelection.h"
95 : #ifdef DEBUG
96 : #include "nsRange.h"
97 : #endif
98 :
99 : #include "nsBindingManager.h"
100 : #include "nsXBLBinding.h"
101 : #include "nsIXBLService.h"
102 : #include "nsPIDOMWindow.h"
103 : #include "nsPIBoxObject.h"
104 : #include "nsIDOMNSElement.h"
105 : #include "nsClientRect.h"
106 : #include "nsSVGUtils.h"
107 : #include "nsLayoutUtils.h"
108 : #include "nsGkAtoms.h"
109 : #include "nsContentUtils.h"
110 : #include "nsIJSContextStack.h"
111 :
112 : #include "nsIServiceManager.h"
113 : #include "nsIDOMEventListener.h"
114 : #include "nsIWebNavigation.h"
115 : #include "nsIBaseWindow.h"
116 : #include "nsIWidget.h"
117 :
118 : #include "jsapi.h"
119 :
120 : #include "nsNodeInfoManager.h"
121 : #include "nsICategoryManager.h"
122 : #include "nsIDOMDocumentType.h"
123 : #include "nsIDOMUserDataHandler.h"
124 : #include "nsGenericHTMLElement.h"
125 : #include "nsIEditor.h"
126 : #include "nsIEditorIMESupport.h"
127 : #include "nsIEditorDocShell.h"
128 : #include "nsEventDispatcher.h"
129 : #include "nsContentCreatorFunctions.h"
130 : #include "nsIControllers.h"
131 : #include "nsLayoutUtils.h"
132 : #include "nsIView.h"
133 : #include "nsIViewManager.h"
134 : #include "nsIScrollableFrame.h"
135 : #include "nsXBLInsertionPoint.h"
136 : #include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */
137 : #include "nsCSSRuleProcessor.h"
138 : #include "nsRuleProcessorData.h"
139 : #include "nsAsyncDOMEvent.h"
140 : #include "nsTextNode.h"
141 : #include "dombindings.h"
142 :
143 : #ifdef MOZ_XUL
144 : #include "nsIXULDocument.h"
145 : #endif /* MOZ_XUL */
146 :
147 : #include "nsCycleCollectionParticipant.h"
148 : #include "nsCCUncollectableMarker.h"
149 :
150 : #include "mozAutoDocUpdate.h"
151 :
152 : #include "nsCSSParser.h"
153 : #include "prprf.h"
154 :
155 : #include "nsSVGFeatures.h"
156 : #include "nsWrapperCacheInlines.h"
157 : #include "nsCycleCollector.h"
158 : #include "xpcpublic.h"
159 : #include "xpcprivate.h"
160 : #include "nsLayoutStatics.h"
161 : #include "mozilla/Telemetry.h"
162 :
163 : #include "mozilla/CORSMode.h"
164 :
165 : using namespace mozilla;
166 : using namespace mozilla::dom;
167 :
168 : NS_DEFINE_IID(kThisPtrOffsetsSID, NS_THISPTROFFSETS_SID);
169 :
170 : PRInt32 nsIContent::sTabFocusModel = eTabFocus_any;
171 : bool nsIContent::sTabFocusModelAppliesToXUL = false;
172 : PRUint32 nsMutationGuard::sMutationCount = 0;
173 :
174 : nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
175 :
176 : void
177 125499 : nsWrapperCache::RemoveExpandoObject()
178 : {
179 125499 : JSObject *expando = GetExpandoObjectPreserveColor();
180 125499 : if (expando) {
181 0 : JSCompartment *compartment = js::GetObjectCompartment(expando);
182 : xpc::CompartmentPrivate *priv =
183 0 : static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
184 0 : priv->RemoveDOMExpandoObject(expando);
185 : }
186 125499 : }
187 :
188 : //----------------------------------------------------------------------
189 :
190 10489 : nsINode::nsSlots::~nsSlots()
191 : {
192 4609 : if (mChildNodes) {
193 0 : mChildNodes->DropReference();
194 0 : NS_RELEASE(mChildNodes);
195 : }
196 :
197 4609 : if (mWeakReference) {
198 0 : mWeakReference->NoticeNodeDestruction();
199 : }
200 11760 : }
201 :
202 : void
203 4988 : nsINode::nsSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
204 : {
205 4988 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildNodes");
206 4988 : cb.NoteXPCOMChild(mChildNodes);
207 4988 : }
208 :
209 : void
210 4609 : nsINode::nsSlots::Unlink()
211 : {
212 4609 : if (mChildNodes) {
213 1527 : mChildNodes->DropReference();
214 1527 : NS_RELEASE(mChildNodes);
215 : }
216 4609 : }
217 :
218 : //----------------------------------------------------------------------
219 :
220 230562 : nsINode::~nsINode()
221 : {
222 115281 : NS_ASSERTION(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
223 230562 : }
224 :
225 : void*
226 0 : nsINode::GetProperty(PRUint16 aCategory, nsIAtom *aPropertyName,
227 : nsresult *aStatus) const
228 : {
229 : return OwnerDoc()->PropertyTable(aCategory)->GetProperty(this, aPropertyName,
230 0 : aStatus);
231 : }
232 :
233 : nsresult
234 0 : nsINode::SetProperty(PRUint16 aCategory, nsIAtom *aPropertyName, void *aValue,
235 : NSPropertyDtorFunc aDtor, bool aTransfer,
236 : void **aOldValue)
237 : {
238 : nsresult rv = OwnerDoc()->PropertyTable(aCategory)->SetProperty(this,
239 : aPropertyName,
240 : aValue, aDtor,
241 : nsnull,
242 : aTransfer,
243 0 : aOldValue);
244 0 : if (NS_SUCCEEDED(rv)) {
245 0 : SetFlags(NODE_HAS_PROPERTIES);
246 : }
247 :
248 0 : return rv;
249 : }
250 :
251 : void
252 0 : nsINode::DeleteProperty(PRUint16 aCategory, nsIAtom *aPropertyName)
253 : {
254 0 : OwnerDoc()->PropertyTable(aCategory)->DeleteProperty(this, aPropertyName);
255 0 : }
256 :
257 : void*
258 0 : nsINode::UnsetProperty(PRUint16 aCategory, nsIAtom *aPropertyName,
259 : nsresult *aStatus)
260 : {
261 : return OwnerDoc()->PropertyTable(aCategory)->UnsetProperty(this,
262 : aPropertyName,
263 0 : aStatus);
264 : }
265 :
266 : nsINode::nsSlots*
267 1273 : nsINode::CreateSlots()
268 : {
269 1273 : return new nsSlots();
270 : }
271 :
272 : bool
273 49496 : nsINode::IsEditableInternal() const
274 : {
275 49496 : if (HasFlag(NODE_IS_EDITABLE)) {
276 : // The node is in an editable contentEditable subtree.
277 5 : return true;
278 : }
279 :
280 49491 : nsIDocument *doc = GetCurrentDoc();
281 :
282 : // Check if the node is in a document and the document is in designMode.
283 49491 : return doc && doc->HasFlag(NODE_IS_EDITABLE);
284 : }
285 :
286 0 : static nsIContent* GetEditorRootContent(nsIEditor* aEditor)
287 : {
288 0 : nsCOMPtr<nsIDOMElement> rootElement;
289 0 : aEditor->GetRootElement(getter_AddRefs(rootElement));
290 0 : nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElement));
291 0 : return rootContent;
292 : }
293 :
294 : nsIContent*
295 0 : nsINode::GetTextEditorRootContent(nsIEditor** aEditor)
296 : {
297 0 : if (aEditor)
298 0 : *aEditor = nsnull;
299 0 : for (nsINode* node = this; node; node = node->GetNodeParent()) {
300 0 : if (!node->IsElement() ||
301 0 : !node->AsElement()->IsHTML())
302 0 : continue;
303 :
304 0 : nsCOMPtr<nsIEditor> editor;
305 : static_cast<nsGenericHTMLElement*>(node)->
306 0 : GetEditorInternal(getter_AddRefs(editor));
307 0 : if (!editor)
308 0 : continue;
309 :
310 0 : nsIContent* rootContent = GetEditorRootContent(editor);
311 0 : if (aEditor)
312 0 : editor.swap(*aEditor);
313 0 : return rootContent;
314 : }
315 0 : return nsnull;
316 : }
317 :
318 0 : static nsIEditor* GetHTMLEditor(nsPresContext* aPresContext)
319 : {
320 0 : nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
321 0 : nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(container));
322 : bool isEditable;
323 0 : if (!editorDocShell ||
324 0 : NS_FAILED(editorDocShell->GetEditable(&isEditable)) || !isEditable)
325 0 : return nsnull;
326 :
327 0 : nsCOMPtr<nsIEditor> editor;
328 0 : editorDocShell->GetEditor(getter_AddRefs(editor));
329 0 : return editor;
330 : }
331 :
332 0 : static nsIContent* GetRootForContentSubtree(nsIContent* aContent)
333 : {
334 0 : NS_ENSURE_TRUE(aContent, nsnull);
335 0 : nsIContent* stop = aContent->GetBindingParent();
336 0 : while (aContent) {
337 0 : nsIContent* parent = aContent->GetParent();
338 0 : if (parent == stop) {
339 0 : break;
340 : }
341 0 : aContent = parent;
342 : }
343 0 : return aContent;
344 : }
345 :
346 : nsIContent*
347 0 : nsINode::GetSelectionRootContent(nsIPresShell* aPresShell)
348 : {
349 0 : NS_ENSURE_TRUE(aPresShell, nsnull);
350 :
351 0 : if (IsNodeOfType(eDOCUMENT))
352 0 : return static_cast<nsIDocument*>(this)->GetRootElement();
353 0 : if (!IsNodeOfType(eCONTENT))
354 0 : return nsnull;
355 :
356 0 : if (GetCurrentDoc() != aPresShell->GetDocument()) {
357 0 : return nsnull;
358 : }
359 :
360 0 : if (static_cast<nsIContent*>(this)->HasIndependentSelection()) {
361 : // This node should be a descendant of input/textarea editor.
362 0 : nsIContent* content = GetTextEditorRootContent();
363 0 : if (content)
364 0 : return content;
365 : }
366 :
367 0 : nsPresContext* presContext = aPresShell->GetPresContext();
368 0 : if (presContext) {
369 0 : nsIEditor* editor = GetHTMLEditor(presContext);
370 0 : if (editor) {
371 : // This node is in HTML editor.
372 0 : nsIDocument* doc = GetCurrentDoc();
373 0 : if (!doc || doc->HasFlag(NODE_IS_EDITABLE) ||
374 0 : !HasFlag(NODE_IS_EDITABLE)) {
375 0 : nsIContent* editorRoot = GetEditorRootContent(editor);
376 0 : NS_ENSURE_TRUE(editorRoot, nsnull);
377 0 : return nsContentUtils::IsInSameAnonymousTree(this, editorRoot) ?
378 : editorRoot :
379 0 : GetRootForContentSubtree(static_cast<nsIContent*>(this));
380 : }
381 : // If the document isn't editable but this is editable, this is in
382 : // contenteditable. Use the editing host element for selection root.
383 0 : return static_cast<nsIContent*>(this)->GetEditingHost();
384 : }
385 : }
386 :
387 0 : nsRefPtr<nsFrameSelection> fs = aPresShell->FrameSelection();
388 0 : nsIContent* content = fs->GetLimiter();
389 0 : if (!content) {
390 0 : content = fs->GetAncestorLimiter();
391 0 : if (!content) {
392 0 : nsIDocument* doc = aPresShell->GetDocument();
393 0 : NS_ENSURE_TRUE(doc, nsnull);
394 0 : content = doc->GetRootElement();
395 0 : if (!content)
396 0 : return nsnull;
397 : }
398 : }
399 :
400 : // This node might be in another subtree, if so, we should find this subtree's
401 : // root. Otherwise, we can return the content simply.
402 0 : NS_ENSURE_TRUE(content, nsnull);
403 0 : return nsContentUtils::IsInSameAnonymousTree(this, content) ?
404 0 : content : GetRootForContentSubtree(static_cast<nsIContent*>(this));
405 : }
406 :
407 : nsINodeList*
408 9178 : nsINode::GetChildNodesList()
409 : {
410 9178 : nsSlots *slots = GetSlots();
411 9178 : if (!slots) {
412 0 : return nsnull;
413 : }
414 :
415 9178 : if (!slots->mChildNodes) {
416 1527 : slots->mChildNodes = new nsChildContentList(this);
417 1527 : if (slots->mChildNodes) {
418 1527 : NS_ADDREF(slots->mChildNodes);
419 : }
420 : }
421 :
422 9178 : return slots->mChildNodes;
423 : }
424 :
425 : #ifdef DEBUG
426 : void
427 57871 : nsINode::CheckNotNativeAnonymous() const
428 : {
429 57871 : if (!IsNodeOfType(eCONTENT))
430 2920 : return;
431 54951 : nsIContent* content = static_cast<const nsIContent *>(this)->GetBindingParent();
432 109902 : while (content) {
433 0 : if (content->IsRootOfNativeAnonymousSubtree()) {
434 0 : NS_ERROR("Element not marked to be in native anonymous subtree!");
435 0 : break;
436 : }
437 0 : content = content->GetBindingParent();
438 : }
439 : }
440 : #endif
441 :
442 : nsresult
443 376 : nsINode::GetParentNode(nsIDOMNode** aParentNode)
444 : {
445 376 : *aParentNode = nsnull;
446 :
447 376 : nsINode *parent = GetNodeParent();
448 :
449 376 : return parent ? CallQueryInterface(parent, aParentNode) : NS_OK;
450 : }
451 :
452 : nsresult
453 0 : nsINode::GetParentElement(nsIDOMElement** aParentElement)
454 : {
455 0 : *aParentElement = nsnull;
456 0 : nsINode* parent = GetElementParent();
457 0 : return parent ? CallQueryInterface(parent, aParentElement) : NS_OK;
458 : }
459 :
460 : nsresult
461 4589 : nsINode::GetChildNodes(nsIDOMNodeList** aChildNodes)
462 : {
463 4589 : *aChildNodes = GetChildNodesList();
464 4589 : if (!*aChildNodes) {
465 0 : return NS_ERROR_OUT_OF_MEMORY;
466 : }
467 :
468 4589 : NS_ADDREF(*aChildNodes);
469 :
470 4589 : return NS_OK;
471 : }
472 :
473 : nsresult
474 266 : nsINode::GetFirstChild(nsIDOMNode** aNode)
475 : {
476 266 : nsIContent* child = GetFirstChild();
477 266 : if (child) {
478 258 : return CallQueryInterface(child, aNode);
479 : }
480 :
481 8 : *aNode = nsnull;
482 :
483 8 : return NS_OK;
484 : }
485 :
486 : nsresult
487 72 : nsINode::GetLastChild(nsIDOMNode** aNode)
488 : {
489 72 : nsIContent* child = GetLastChild();
490 72 : if (child) {
491 10 : return CallQueryInterface(child, aNode);
492 : }
493 :
494 62 : *aNode = nsnull;
495 :
496 62 : return NS_OK;
497 : }
498 :
499 : nsresult
500 0 : nsINode::GetPreviousSibling(nsIDOMNode** aPrevSibling)
501 : {
502 0 : *aPrevSibling = nsnull;
503 :
504 0 : nsIContent *sibling = GetPreviousSibling();
505 :
506 0 : return sibling ? CallQueryInterface(sibling, aPrevSibling) : NS_OK;
507 : }
508 :
509 : nsresult
510 5122 : nsINode::GetNextSibling(nsIDOMNode** aNextSibling)
511 : {
512 5122 : *aNextSibling = nsnull;
513 :
514 5122 : nsIContent *sibling = GetNextSibling();
515 :
516 5122 : return sibling ? CallQueryInterface(sibling, aNextSibling) : NS_OK;
517 : }
518 :
519 : nsresult
520 365 : nsINode::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
521 : {
522 365 : *aOwnerDocument = nsnull;
523 :
524 365 : nsIDocument *ownerDoc = GetOwnerDocument();
525 :
526 365 : return ownerDoc ? CallQueryInterface(ownerDoc, aOwnerDocument) : NS_OK;
527 : }
528 :
529 : nsresult
530 133 : nsINode::RemoveChild(nsINode *aOldChild)
531 : {
532 133 : if (!aOldChild) {
533 0 : return NS_ERROR_NULL_POINTER;
534 : }
535 :
536 133 : if (IsNodeOfType(eDATA_NODE)) {
537 0 : return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
538 : }
539 :
540 133 : if (aOldChild && aOldChild->GetNodeParent() == this) {
541 133 : nsContentUtils::MaybeFireNodeRemoved(aOldChild, this, OwnerDoc());
542 : }
543 :
544 133 : PRInt32 index = IndexOf(aOldChild);
545 133 : if (index == -1) {
546 : // aOldChild isn't one of our children.
547 0 : return NS_ERROR_DOM_NOT_FOUND_ERR;
548 : }
549 :
550 133 : return RemoveChildAt(index, true);
551 : }
552 :
553 : nsresult
554 13 : nsINode::ReplaceOrInsertBefore(bool aReplace, nsIDOMNode* aNewChild,
555 : nsIDOMNode* aRefChild, nsIDOMNode** aReturn)
556 : {
557 26 : nsCOMPtr<nsINode> newChild = do_QueryInterface(aNewChild);
558 :
559 : nsresult rv;
560 26 : nsCOMPtr<nsINode> refChild;
561 13 : if (aRefChild) {
562 4 : refChild = do_QueryInterface(aRefChild, &rv);
563 4 : NS_ENSURE_SUCCESS(rv, rv);
564 : }
565 :
566 13 : rv = ReplaceOrInsertBefore(aReplace, newChild, refChild);
567 13 : if (NS_SUCCEEDED(rv)) {
568 13 : NS_ADDREF(*aReturn = aReplace ? aRefChild : aNewChild);
569 : }
570 :
571 13 : return rv;
572 : }
573 :
574 : nsresult
575 10 : nsINode::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
576 : {
577 20 : nsCOMPtr<nsIContent> oldChild = do_QueryInterface(aOldChild);
578 10 : nsresult rv = RemoveChild(oldChild);
579 10 : if (NS_SUCCEEDED(rv)) {
580 10 : NS_ADDREF(*aReturn = aOldChild);
581 : }
582 10 : return rv;
583 : }
584 :
585 : nsresult
586 21 : nsINode::Normalize()
587 : {
588 : // First collect list of nodes to be removed
589 42 : nsAutoTArray<nsCOMPtr<nsIContent>, 50> nodes;
590 :
591 21 : bool canMerge = false;
592 98 : for (nsIContent* node = this->GetFirstChild();
593 : node;
594 77 : node = node->GetNextNode(this)) {
595 77 : if (node->NodeType() != nsIDOMNode::TEXT_NODE) {
596 14 : canMerge = false;
597 14 : continue;
598 : }
599 :
600 63 : if (canMerge || node->TextLength() == 0) {
601 : // No need to touch canMerge. That way we can merge across empty
602 : // textnodes if and only if the node before is a textnode
603 26 : nodes.AppendElement(node);
604 : }
605 : else {
606 37 : canMerge = true;
607 : }
608 :
609 : // If there's no following sibling, then we need to ensure that we don't
610 : // collect following siblings of our (grand)parent as to-be-removed
611 63 : canMerge = canMerge && !!node->GetNextSibling();
612 : }
613 :
614 21 : if (nodes.IsEmpty()) {
615 7 : return NS_OK;
616 : }
617 :
618 : // We're relying on mozAutoSubtreeModified to keep the doc alive here.
619 14 : nsIDocument* doc = OwnerDoc();
620 :
621 : // Batch possible DOMSubtreeModified events.
622 28 : mozAutoSubtreeModified subtree(doc, nsnull);
623 :
624 : // Fire all DOMNodeRemoved events. Optimize the common case of there being
625 : // no listeners
626 : bool hasRemoveListeners = nsContentUtils::
627 14 : HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED);
628 14 : if (hasRemoveListeners) {
629 40 : for (PRUint32 i = 0; i < nodes.Length(); ++i) {
630 52 : nsContentUtils::MaybeFireNodeRemoved(nodes[i], nodes[i]->GetNodeParent(),
631 52 : doc);
632 : }
633 : }
634 :
635 28 : mozAutoDocUpdate batch(doc, UPDATE_CONTENT_MODEL, true);
636 :
637 : // Merge and remove all nodes
638 28 : nsAutoString tmpStr;
639 40 : for (PRUint32 i = 0; i < nodes.Length(); ++i) {
640 26 : nsIContent* node = nodes[i];
641 : // Merge with previous node unless empty
642 26 : const nsTextFragment* text = node->GetText();
643 26 : if (text->GetLength()) {
644 9 : nsIContent* target = node->GetPreviousSibling();
645 9 : NS_ASSERTION((target && target->NodeType() == nsIDOMNode::TEXT_NODE) ||
646 : hasRemoveListeners,
647 : "Should always have a previous text sibling unless "
648 : "mutation events messed us up");
649 18 : if (!hasRemoveListeners ||
650 9 : (target && target->NodeType() == nsIDOMNode::TEXT_NODE)) {
651 9 : nsTextNode* t = static_cast<nsTextNode*>(target);
652 9 : if (text->Is2b()) {
653 0 : t->AppendTextForNormalize(text->Get2b(), text->GetLength(), true, node);
654 : }
655 : else {
656 9 : tmpStr.Truncate();
657 9 : text->AppendTo(tmpStr);
658 9 : t->AppendTextForNormalize(tmpStr.get(), tmpStr.Length(), true, node);
659 : }
660 : }
661 : }
662 :
663 : // Remove node
664 52 : nsCOMPtr<nsINode> parent = node->GetNodeParent();
665 26 : NS_ASSERTION(parent || hasRemoveListeners,
666 : "Should always have a parent unless "
667 : "mutation events messed us up");
668 26 : if (parent) {
669 26 : parent->RemoveChildAt(parent->IndexOf(node), true);
670 : }
671 : }
672 :
673 14 : return NS_OK;
674 : }
675 :
676 : nsresult
677 0 : nsINode::GetDOMBaseURI(nsAString &aURI) const
678 : {
679 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
680 :
681 0 : nsCAutoString spec;
682 0 : if (baseURI) {
683 0 : baseURI->GetSpec(spec);
684 : }
685 :
686 0 : CopyUTF8toUTF16(spec, aURI);
687 :
688 0 : return NS_OK;
689 : }
690 :
691 : nsresult
692 0 : nsINode::LookupPrefix(const nsAString& aNamespaceURI, nsAString& aPrefix)
693 : {
694 0 : Element *element = GetNameSpaceElement();
695 0 : if (element) {
696 : // XXX Waiting for DOM spec to list error codes.
697 :
698 : // Trace up the content parent chain looking for the namespace
699 : // declaration that defines the aNamespaceURI namespace. Once found,
700 : // return the prefix (i.e. the attribute localName).
701 0 : for (nsIContent* content = element; content;
702 0 : content = content->GetParent()) {
703 0 : PRUint32 attrCount = content->GetAttrCount();
704 :
705 0 : for (PRUint32 i = 0; i < attrCount; ++i) {
706 0 : const nsAttrName* name = content->GetAttrNameAt(i);
707 :
708 0 : if (name->NamespaceEquals(kNameSpaceID_XMLNS) &&
709 : content->AttrValueIs(kNameSpaceID_XMLNS, name->LocalName(),
710 0 : aNamespaceURI, eCaseMatters)) {
711 : // If the localName is "xmlns", the prefix we output should be
712 : // null.
713 0 : nsIAtom *localName = name->LocalName();
714 :
715 0 : if (localName != nsGkAtoms::xmlns) {
716 0 : localName->ToString(aPrefix);
717 : }
718 : else {
719 0 : SetDOMStringToNull(aPrefix);
720 : }
721 0 : return NS_OK;
722 : }
723 : }
724 : }
725 : }
726 :
727 0 : SetDOMStringToNull(aPrefix);
728 :
729 0 : return NS_OK;
730 : }
731 :
732 : static nsresult
733 0 : SetUserDataProperty(PRUint16 aCategory, nsINode *aNode, nsIAtom *aKey,
734 : nsISupports* aValue, void** aOldValue)
735 : {
736 : nsresult rv = aNode->SetProperty(aCategory, aKey, aValue,
737 : nsPropertyTable::SupportsDtorFunc, true,
738 0 : aOldValue);
739 0 : NS_ENSURE_SUCCESS(rv, rv);
740 :
741 : // Property table owns it now.
742 0 : NS_ADDREF(aValue);
743 :
744 0 : return NS_OK;
745 : }
746 :
747 : nsresult
748 0 : nsINode::SetUserData(const nsAString &aKey, nsIVariant *aData,
749 : nsIDOMUserDataHandler *aHandler, nsIVariant **aResult)
750 : {
751 0 : *aResult = nsnull;
752 :
753 0 : nsCOMPtr<nsIAtom> key = do_GetAtom(aKey);
754 0 : if (!key) {
755 0 : return NS_ERROR_OUT_OF_MEMORY;
756 : }
757 :
758 : nsresult rv;
759 : void *data;
760 0 : if (aData) {
761 0 : rv = SetUserDataProperty(DOM_USER_DATA, this, key, aData, &data);
762 0 : NS_ENSURE_SUCCESS(rv, rv);
763 : }
764 : else {
765 0 : data = UnsetProperty(DOM_USER_DATA, key);
766 : }
767 :
768 : // Take over ownership of the old data from the property table.
769 0 : nsCOMPtr<nsIVariant> oldData = dont_AddRef(static_cast<nsIVariant*>(data));
770 :
771 0 : if (aData && aHandler) {
772 0 : nsCOMPtr<nsIDOMUserDataHandler> oldHandler;
773 : rv = SetUserDataProperty(DOM_USER_DATA_HANDLER, this, key, aHandler,
774 0 : getter_AddRefs(oldHandler));
775 0 : if (NS_FAILED(rv)) {
776 : // We failed to set the handler, remove the data.
777 0 : DeleteProperty(DOM_USER_DATA, key);
778 :
779 0 : return rv;
780 0 : }
781 : }
782 : else {
783 0 : DeleteProperty(DOM_USER_DATA_HANDLER, key);
784 : }
785 :
786 0 : oldData.swap(*aResult);
787 :
788 0 : return NS_OK;
789 : }
790 :
791 : PRUint16
792 21 : nsINode::CompareDocPosition(nsINode* aOtherNode)
793 : {
794 21 : NS_PRECONDITION(aOtherNode, "don't pass null");
795 :
796 21 : if (this == aOtherNode) {
797 0 : return 0;
798 : }
799 :
800 42 : nsAutoTArray<nsINode*, 32> parents1, parents2;
801 :
802 21 : nsINode *node1 = aOtherNode, *node2 = this;
803 :
804 : // Check if either node is an attribute
805 21 : nsIAttribute* attr1 = nsnull;
806 21 : if (node1->IsNodeOfType(nsINode::eATTRIBUTE)) {
807 0 : attr1 = static_cast<nsIAttribute*>(node1);
808 0 : nsIContent* elem = attr1->GetContent();
809 : // If there is an owner element add the attribute
810 : // to the chain and walk up to the element
811 0 : if (elem) {
812 0 : node1 = elem;
813 0 : parents1.AppendElement(static_cast<nsINode*>(attr1));
814 : }
815 : }
816 21 : if (node2->IsNodeOfType(nsINode::eATTRIBUTE)) {
817 0 : nsIAttribute* attr2 = static_cast<nsIAttribute*>(node2);
818 0 : nsIContent* elem = attr2->GetContent();
819 0 : if (elem == node1 && attr1) {
820 : // Both nodes are attributes on the same element.
821 : // Compare position between the attributes.
822 :
823 : PRUint32 i;
824 : const nsAttrName* attrName;
825 0 : for (i = 0; (attrName = elem->GetAttrNameAt(i)); ++i) {
826 0 : if (attrName->Equals(attr1->NodeInfo())) {
827 0 : NS_ASSERTION(!attrName->Equals(attr2->NodeInfo()),
828 : "Different attrs at same position");
829 : return nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
830 0 : nsIDOMNode::DOCUMENT_POSITION_PRECEDING;
831 : }
832 0 : if (attrName->Equals(attr2->NodeInfo())) {
833 : return nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
834 0 : nsIDOMNode::DOCUMENT_POSITION_FOLLOWING;
835 : }
836 : }
837 0 : NS_NOTREACHED("neither attribute in the element");
838 0 : return nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED;
839 : }
840 :
841 0 : if (elem) {
842 0 : node2 = elem;
843 0 : parents2.AppendElement(static_cast<nsINode*>(attr2));
844 : }
845 : }
846 :
847 : // We now know that both nodes are either nsIContents or nsIDocuments.
848 : // If either node started out as an attribute, that attribute will have
849 : // the same relative position as its ownerElement, except if the
850 : // ownerElement ends up being the container for the other node
851 :
852 : // Build the chain of parents
853 75 : do {
854 75 : parents1.AppendElement(node1);
855 75 : node1 = node1->GetNodeParent();
856 : } while (node1);
857 75 : do {
858 75 : parents2.AppendElement(node2);
859 75 : node2 = node2->GetNodeParent();
860 : } while (node2);
861 :
862 : // Check if the nodes are disconnected.
863 21 : PRUint32 pos1 = parents1.Length();
864 21 : PRUint32 pos2 = parents2.Length();
865 21 : nsINode* top1 = parents1.ElementAt(--pos1);
866 21 : nsINode* top2 = parents2.ElementAt(--pos2);
867 21 : if (top1 != top2) {
868 : return top1 < top2 ?
869 : (nsIDOMNode::DOCUMENT_POSITION_PRECEDING |
870 : nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED |
871 : nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC) :
872 : (nsIDOMNode::DOCUMENT_POSITION_FOLLOWING |
873 : nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED |
874 0 : nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
875 : }
876 :
877 : // Find where the parent chain differs and check indices in the parent.
878 21 : nsINode* parent = top1;
879 : PRUint32 len;
880 42 : for (len = NS_MIN(pos1, pos2); len > 0; --len) {
881 40 : nsINode* child1 = parents1.ElementAt(--pos1);
882 40 : nsINode* child2 = parents2.ElementAt(--pos2);
883 40 : if (child1 != child2) {
884 : // child1 or child2 can be an attribute here. This will work fine since
885 : // IndexOf will return -1 for the attribute making the attribute be
886 : // considered before any child.
887 19 : return parent->IndexOf(child1) < parent->IndexOf(child2) ?
888 : static_cast<PRUint16>(nsIDOMNode::DOCUMENT_POSITION_PRECEDING) :
889 19 : static_cast<PRUint16>(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING);
890 : }
891 21 : parent = child1;
892 : }
893 :
894 : // We hit the end of one of the parent chains without finding a difference
895 : // between the chains. That must mean that one node is an ancestor of the
896 : // other. The one with the shortest chain must be the ancestor.
897 : return pos1 < pos2 ?
898 : (nsIDOMNode::DOCUMENT_POSITION_PRECEDING |
899 : nsIDOMNode::DOCUMENT_POSITION_CONTAINS) :
900 : (nsIDOMNode::DOCUMENT_POSITION_FOLLOWING |
901 2 : nsIDOMNode::DOCUMENT_POSITION_CONTAINED_BY);
902 : }
903 :
904 : bool
905 999 : nsINode::IsEqualTo(nsINode* aOther)
906 : {
907 999 : if (!aOther) {
908 0 : return false;
909 : }
910 :
911 1998 : nsAutoString string1, string2;
912 :
913 999 : nsINode* node1 = this;
914 999 : nsINode* node2 = aOther;
915 2613 : do {
916 3605 : PRUint16 nodeType = node1->NodeType();
917 3605 : if (nodeType != node2->NodeType()) {
918 166 : return false;
919 : }
920 :
921 3439 : nsINodeInfo* nodeInfo1 = node1->mNodeInfo;
922 3439 : nsINodeInfo* nodeInfo2 = node2->mNodeInfo;
923 6858 : if (!nodeInfo1->Equals(nodeInfo2) ||
924 3419 : nodeInfo1->GetExtraName() != nodeInfo2->GetExtraName()) {
925 20 : return false;
926 : }
927 :
928 3419 : switch(nodeType) {
929 : case nsIDOMNode::ELEMENT_NODE:
930 : {
931 : // Both are elements (we checked that their nodeinfos are equal). Do the
932 : // check on attributes.
933 1015 : Element* element1 = node1->AsElement();
934 1015 : Element* element2 = node2->AsElement();
935 1015 : PRUint32 attrCount = element1->GetAttrCount();
936 1015 : if (attrCount != element2->GetAttrCount()) {
937 12 : return false;
938 : }
939 :
940 : // Iterate over attributes.
941 1691 : for (PRUint32 i = 0; i < attrCount; ++i) {
942 692 : const nsAttrName* attrName = element1->GetAttrNameAt(i);
943 : #ifdef DEBUG
944 : bool hasAttr =
945 : #endif
946 : element1->GetAttr(attrName->NamespaceID(), attrName->LocalName(),
947 692 : string1);
948 692 : NS_ASSERTION(hasAttr, "Why don't we have an attr?");
949 :
950 692 : if (!element2->AttrValueIs(attrName->NamespaceID(),
951 : attrName->LocalName(),
952 : string1,
953 692 : eCaseMatters)) {
954 4 : return false;
955 : }
956 : }
957 999 : break;
958 : }
959 : case nsIDOMNode::TEXT_NODE:
960 : case nsIDOMNode::COMMENT_NODE:
961 : case nsIDOMNode::CDATA_SECTION_NODE:
962 : case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
963 : {
964 2245 : string1.Truncate();
965 2245 : static_cast<nsIContent*>(node1)->AppendTextTo(string1);
966 2245 : string2.Truncate();
967 2245 : static_cast<nsIContent*>(node2)->AppendTextTo(string2);
968 :
969 2245 : if (!string1.Equals(string2)) {
970 42 : return false;
971 : }
972 :
973 2203 : break;
974 : }
975 : case nsIDOMNode::DOCUMENT_NODE:
976 : case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
977 51 : break;
978 : case nsIDOMNode::ATTRIBUTE_NODE:
979 : {
980 102 : NS_ASSERTION(node1 == this && node2 == aOther,
981 : "Did we come upon an attribute node while walking a "
982 : "subtree?");
983 204 : nsCOMPtr<nsIDOMNode> domNode1 = do_QueryInterface(node1);
984 204 : nsCOMPtr<nsIDOMNode> domNode2 = do_QueryInterface(node2);
985 102 : domNode1->GetNodeValue(string1);
986 102 : domNode2->GetNodeValue(string2);
987 :
988 : // Returning here as to not bother walking subtree. And there is no
989 : // risk that we're half way through walking some other subtree since
990 : // attribute nodes doesn't appear in subtrees.
991 102 : return string1.Equals(string2);
992 : }
993 : case nsIDOMNode::DOCUMENT_TYPE_NODE:
994 : {
995 12 : nsCOMPtr<nsIDOMDocumentType> docType1 = do_QueryInterface(node1);
996 12 : nsCOMPtr<nsIDOMDocumentType> docType2 = do_QueryInterface(node2);
997 :
998 6 : NS_ASSERTION(docType1 && docType2, "Why don't we have a document type node?");
999 :
1000 : // Public ID
1001 6 : docType1->GetPublicId(string1);
1002 6 : docType2->GetPublicId(string2);
1003 6 : if (!string1.Equals(string2)) {
1004 0 : return false;
1005 : }
1006 :
1007 : // System ID
1008 6 : docType1->GetSystemId(string1);
1009 6 : docType2->GetSystemId(string2);
1010 6 : if (!string1.Equals(string2)) {
1011 0 : return false;
1012 : }
1013 :
1014 : // Internal subset
1015 6 : docType1->GetInternalSubset(string1);
1016 6 : docType2->GetInternalSubset(string2);
1017 6 : if (!string1.Equals(string2)) {
1018 0 : return false;
1019 : }
1020 :
1021 6 : break;
1022 : }
1023 : default:
1024 0 : NS_ABORT_IF_FALSE(false, "Unknown node type");
1025 : }
1026 :
1027 3259 : nsINode* nextNode = node1->GetFirstChild();
1028 3259 : if (nextNode) {
1029 519 : node1 = nextNode;
1030 519 : node2 = node2->GetFirstChild();
1031 : }
1032 : else {
1033 2740 : if (node2->GetFirstChild()) {
1034 : // node2 has a firstChild, but node1 doesn't
1035 7 : return false;
1036 : }
1037 :
1038 : // Find next sibling, possibly walking parent chain.
1039 486 : while (1) {
1040 3219 : if (node1 == this) {
1041 639 : NS_ASSERTION(node2 == aOther, "Should have reached the start node "
1042 : "for both trees at the same time");
1043 639 : return true;
1044 : }
1045 :
1046 2580 : nextNode = node1->GetNextSibling();
1047 2580 : if (nextNode) {
1048 2094 : node1 = nextNode;
1049 2094 : node2 = node2->GetNextSibling();
1050 2094 : break;
1051 : }
1052 :
1053 486 : if (node2->GetNextSibling()) {
1054 : // node2 has a nextSibling, but node1 doesn't
1055 0 : return false;
1056 : }
1057 :
1058 486 : node1 = node1->GetNodeParent();
1059 486 : node2 = node2->GetNodeParent();
1060 486 : NS_ASSERTION(node1 && node2, "no parent while walking subtree");
1061 : }
1062 : }
1063 : } while(node2);
1064 :
1065 7 : return false;
1066 : }
1067 :
1068 : nsresult
1069 0 : nsINode::LookupNamespaceURI(const nsAString& aNamespacePrefix,
1070 : nsAString& aNamespaceURI)
1071 : {
1072 0 : Element *element = GetNameSpaceElement();
1073 0 : if (!element ||
1074 0 : NS_FAILED(element->LookupNamespaceURIInternal(aNamespacePrefix,
1075 : aNamespaceURI))) {
1076 0 : SetDOMStringToNull(aNamespaceURI);
1077 : }
1078 :
1079 0 : return NS_OK;
1080 : }
1081 :
1082 11838 : NS_IMPL_DOMTARGET_DEFAULTS(nsINode)
1083 :
1084 : NS_IMETHODIMP
1085 2 : nsINode::AddEventListener(const nsAString& aType,
1086 : nsIDOMEventListener *aListener,
1087 : bool aUseCapture,
1088 : bool aWantsUntrusted,
1089 : PRUint8 aOptionalArgc)
1090 : {
1091 2 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
1092 : "Won't check if this is chrome, you want to set "
1093 : "aWantsUntrusted to false or make the aWantsUntrusted "
1094 : "explicit by making aOptionalArgc non-zero.");
1095 :
1096 4 : if (!aWantsUntrusted &&
1097 : (aOptionalArgc < 2 &&
1098 2 : !nsContentUtils::IsChromeDoc(OwnerDoc()))) {
1099 2 : aWantsUntrusted = true;
1100 : }
1101 :
1102 2 : nsEventListenerManager* listener_manager = GetListenerManager(true);
1103 2 : NS_ENSURE_STATE(listener_manager);
1104 : listener_manager->AddEventListener(aType, aListener, aUseCapture,
1105 2 : aWantsUntrusted);
1106 2 : return NS_OK;
1107 : }
1108 :
1109 : NS_IMETHODIMP
1110 0 : nsINode::AddSystemEventListener(const nsAString& aType,
1111 : nsIDOMEventListener *aListener,
1112 : bool aUseCapture,
1113 : bool aWantsUntrusted,
1114 : PRUint8 aOptionalArgc)
1115 : {
1116 0 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
1117 : "Won't check if this is chrome, you want to set "
1118 : "aWantsUntrusted to false or make the aWantsUntrusted "
1119 : "explicit by making aOptionalArgc non-zero.");
1120 :
1121 0 : if (!aWantsUntrusted &&
1122 : (aOptionalArgc < 2 &&
1123 0 : !nsContentUtils::IsChromeDoc(OwnerDoc()))) {
1124 0 : aWantsUntrusted = true;
1125 : }
1126 :
1127 : return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
1128 0 : aWantsUntrusted);
1129 : }
1130 :
1131 : NS_IMETHODIMP
1132 0 : nsINode::RemoveEventListener(const nsAString& aType,
1133 : nsIDOMEventListener* aListener,
1134 : bool aUseCapture)
1135 : {
1136 0 : nsEventListenerManager* elm = GetListenerManager(false);
1137 0 : if (elm) {
1138 0 : elm->RemoveEventListener(aType, aListener, aUseCapture);
1139 : }
1140 0 : return NS_OK;
1141 : }
1142 :
1143 0 : NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
1144 :
1145 : nsresult
1146 0 : nsINode::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
1147 : {
1148 : // This is only here so that we can use the NS_DECL_NSIDOMTARGET macro
1149 0 : NS_ABORT();
1150 0 : return NS_ERROR_NOT_IMPLEMENTED;
1151 : }
1152 :
1153 : nsresult
1154 5407 : nsINode::DispatchEvent(nsIDOMEvent *aEvent, bool* aRetVal)
1155 : {
1156 : // XXX sXBL/XBL2 issue -- do we really want the owner here? What
1157 : // if that's the XBL document? Would we want its presshell? Or what?
1158 10814 : nsCOMPtr<nsIDocument> document = OwnerDoc();
1159 :
1160 : // Do nothing if the element does not belong to a document
1161 5407 : if (!document) {
1162 0 : *aRetVal = true;
1163 0 : return NS_OK;
1164 : }
1165 :
1166 : // Obtain a presentation shell
1167 5407 : nsIPresShell *shell = document->GetShell();
1168 10814 : nsRefPtr<nsPresContext> context;
1169 5407 : if (shell) {
1170 0 : context = shell->GetPresContext();
1171 : }
1172 :
1173 5407 : nsEventStatus status = nsEventStatus_eIgnore;
1174 : nsresult rv =
1175 : nsEventDispatcher::DispatchDOMEvent(this, nsnull, aEvent, context,
1176 5407 : &status);
1177 5407 : *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
1178 5407 : return rv;
1179 : }
1180 :
1181 : nsresult
1182 6465 : nsINode::PostHandleEvent(nsEventChainPostVisitor& /*aVisitor*/)
1183 : {
1184 6465 : return NS_OK;
1185 : }
1186 :
1187 : nsresult
1188 0 : nsINode::DispatchDOMEvent(nsEvent* aEvent,
1189 : nsIDOMEvent* aDOMEvent,
1190 : nsPresContext* aPresContext,
1191 : nsEventStatus* aEventStatus)
1192 : {
1193 : return nsEventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent,
1194 0 : aPresContext, aEventStatus);
1195 : }
1196 :
1197 : nsEventListenerManager*
1198 27262 : nsINode::GetListenerManager(bool aCreateIfNotFound)
1199 : {
1200 27262 : return nsContentUtils::GetListenerManager(this, aCreateIfNotFound);
1201 : }
1202 :
1203 : nsIScriptContext*
1204 2 : nsINode::GetContextForEventHandlers(nsresult* aRv)
1205 : {
1206 2 : return nsContentUtils::GetContextForEventHandlers(this, aRv);
1207 : }
1208 :
1209 : /* static */
1210 : void
1211 138789 : nsINode::Trace(nsINode *tmp, TraceCallback cb, void *closure)
1212 : {
1213 138789 : nsContentUtils::TraceWrapper(tmp, cb, closure);
1214 138789 : }
1215 :
1216 :
1217 : static
1218 501553 : bool UnoptimizableCCNode(nsINode* aNode)
1219 : {
1220 : const PtrBits problematicFlags = (NODE_IS_ANONYMOUS |
1221 : NODE_IS_IN_ANONYMOUS_SUBTREE |
1222 : NODE_IS_NATIVE_ANONYMOUS_ROOT |
1223 : NODE_MAY_BE_IN_BINDING_MNGR |
1224 501553 : NODE_IS_INSERTION_PARENT);
1225 501553 : return aNode->HasFlag(problematicFlags) ||
1226 501553 : aNode->NodeType() == nsIDOMNode::ATTRIBUTE_NODE ||
1227 : // For strange cases like xbl:content/xbl:children
1228 501553 : (aNode->IsElement() &&
1229 1504659 : aNode->AsElement()->IsInNamespace(kNameSpaceID_XBL));
1230 : }
1231 :
1232 : /* static */
1233 : bool
1234 138775 : nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
1235 : {
1236 138775 : nsIDocument *currentDoc = tmp->GetCurrentDoc();
1237 274435 : if (currentDoc &&
1238 135660 : nsCCUncollectableMarker::InGeneration(cb, currentDoc->GetMarkedCCGeneration())) {
1239 0 : return false;
1240 : }
1241 :
1242 138775 : if (nsCCUncollectableMarker::sGeneration) {
1243 : // If we're black no need to traverse.
1244 56350 : if (tmp->IsBlack() || tmp->InCCBlackTree()) {
1245 0 : return false;
1246 : }
1247 :
1248 56350 : if (!UnoptimizableCCNode(tmp)) {
1249 : // If we're in a black document, return early.
1250 56350 : if ((currentDoc && currentDoc->IsBlack())) {
1251 0 : return false;
1252 : }
1253 : // If we're not in anonymous content and we have a black parent,
1254 : // return early.
1255 56350 : nsIContent* parent = tmp->GetParent();
1256 56350 : if (parent && !UnoptimizableCCNode(parent) && parent->IsBlack()) {
1257 0 : NS_ABORT_IF_FALSE(parent->IndexOf(tmp) >= 0, "Parent doesn't own us?");
1258 0 : return false;
1259 : }
1260 : }
1261 : }
1262 :
1263 138775 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
1264 138775 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
1265 :
1266 138775 : nsSlots *slots = tmp->GetExistingSlots();
1267 138775 : if (slots) {
1268 4988 : slots->Traverse(cb);
1269 : }
1270 :
1271 138775 : if (tmp->HasProperties()) {
1272 0 : nsNodeUtils::TraverseUserData(tmp, cb);
1273 : }
1274 :
1275 276088 : if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
1276 137313 : tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
1277 3 : nsContentUtils::TraverseListenerManager(tmp, cb);
1278 : }
1279 :
1280 138775 : return true;
1281 : }
1282 :
1283 : /* static */
1284 : void
1285 114987 : nsINode::Unlink(nsINode *tmp)
1286 : {
1287 114987 : nsContentUtils::ReleaseWrapper(tmp, tmp);
1288 :
1289 114987 : nsSlots *slots = tmp->GetExistingSlots();
1290 114987 : if (slots) {
1291 4609 : slots->Unlink();
1292 : }
1293 :
1294 228703 : if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
1295 113716 : tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
1296 0 : nsContentUtils::RemoveListenerManager(tmp);
1297 0 : tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
1298 : }
1299 :
1300 114987 : if (tmp->HasProperties()) {
1301 0 : nsNodeUtils::UnlinkUserData(tmp);
1302 : }
1303 114987 : }
1304 :
1305 : //----------------------------------------------------------------------
1306 :
1307 : nsEventStates
1308 11603 : Element::IntrinsicState() const
1309 : {
1310 11603 : return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE :
1311 23206 : NS_EVENT_STATE_MOZ_READONLY;
1312 : }
1313 :
1314 : void
1315 0 : Element::NotifyStateChange(nsEventStates aStates)
1316 : {
1317 0 : nsIDocument* doc = GetCurrentDoc();
1318 0 : if (doc) {
1319 0 : nsAutoScriptBlocker scriptBlocker;
1320 0 : doc->ContentStateChanged(this, aStates);
1321 : }
1322 0 : }
1323 :
1324 : void
1325 0 : Element::UpdateLinkState(nsEventStates aState)
1326 : {
1327 0 : NS_ABORT_IF_FALSE(!aState.HasAtLeastOneOfStates(~(NS_EVENT_STATE_VISITED |
1328 : NS_EVENT_STATE_UNVISITED)),
1329 : "Unexpected link state bits");
1330 : mState =
1331 : (mState & ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) |
1332 0 : aState;
1333 0 : }
1334 :
1335 : void
1336 11603 : Element::UpdateState(bool aNotify)
1337 : {
1338 11603 : nsEventStates oldState = mState;
1339 11603 : mState = IntrinsicState() | (oldState & ESM_MANAGED_STATES);
1340 11603 : if (aNotify) {
1341 1874 : nsEventStates changedStates = oldState ^ mState;
1342 1874 : if (!changedStates.IsEmpty()) {
1343 0 : nsIDocument* doc = GetCurrentDoc();
1344 0 : if (doc) {
1345 0 : nsAutoScriptBlocker scriptBlocker;
1346 0 : doc->ContentStateChanged(this, changedStates);
1347 : }
1348 : }
1349 : }
1350 11603 : }
1351 :
1352 : void
1353 74006 : nsIContent::UpdateEditableState(bool aNotify)
1354 : {
1355 : // Guaranteed to be non-element content
1356 74006 : NS_ASSERTION(!IsElement(), "What happened here?");
1357 74006 : nsIContent *parent = GetParent();
1358 :
1359 74006 : SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
1360 74006 : }
1361 :
1362 : void
1363 37893 : nsGenericElement::UpdateEditableState(bool aNotify)
1364 : {
1365 37893 : nsIContent *parent = GetParent();
1366 :
1367 37893 : SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
1368 37893 : if (aNotify) {
1369 0 : UpdateState(aNotify);
1370 : } else {
1371 : // Avoid calling UpdateState in this very common case, because
1372 : // this gets called for pretty much every single element on
1373 : // insertion into the document and UpdateState can be slow for
1374 : // some kinds of elements even when not notifying.
1375 37893 : if (IsEditable()) {
1376 0 : RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
1377 0 : AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
1378 : } else {
1379 37893 : RemoveStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
1380 37893 : AddStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
1381 : }
1382 : }
1383 37893 : }
1384 :
1385 : nsEventStates
1386 0 : Element::StyleStateFromLocks() const
1387 : {
1388 0 : nsEventStates locks = LockedStyleStates();
1389 0 : nsEventStates state = mState | locks;
1390 :
1391 0 : if (locks.HasState(NS_EVENT_STATE_VISITED)) {
1392 0 : return state & ~NS_EVENT_STATE_UNVISITED;
1393 : }
1394 0 : if (locks.HasState(NS_EVENT_STATE_UNVISITED)) {
1395 0 : return state & ~NS_EVENT_STATE_VISITED;
1396 : }
1397 0 : return state;
1398 : }
1399 :
1400 : nsEventStates
1401 0 : Element::LockedStyleStates() const
1402 : {
1403 : nsEventStates *locks =
1404 0 : static_cast<nsEventStates*> (GetProperty(nsGkAtoms::lockedStyleStates));
1405 0 : if (locks) {
1406 0 : return *locks;
1407 : }
1408 0 : return nsEventStates();
1409 : }
1410 :
1411 : static void
1412 0 : nsEventStatesPropertyDtor(void *aObject, nsIAtom *aProperty,
1413 : void *aPropertyValue, void *aData)
1414 : {
1415 0 : nsEventStates *states = static_cast<nsEventStates*>(aPropertyValue);
1416 : delete states;
1417 0 : }
1418 :
1419 : void
1420 0 : Element::NotifyStyleStateChange(nsEventStates aStates)
1421 : {
1422 0 : nsIDocument* doc = GetCurrentDoc();
1423 0 : if (doc) {
1424 0 : nsIPresShell *presShell = doc->GetShell();
1425 0 : if (presShell) {
1426 0 : nsAutoScriptBlocker scriptBlocker;
1427 0 : presShell->ContentStateChanged(doc, this, aStates);
1428 : }
1429 : }
1430 0 : }
1431 :
1432 : void
1433 0 : Element::LockStyleStates(nsEventStates aStates)
1434 : {
1435 0 : nsEventStates *locks = new nsEventStates(LockedStyleStates());
1436 :
1437 0 : *locks |= aStates;
1438 :
1439 0 : if (aStates.HasState(NS_EVENT_STATE_VISITED)) {
1440 0 : *locks &= ~NS_EVENT_STATE_UNVISITED;
1441 : }
1442 0 : if (aStates.HasState(NS_EVENT_STATE_UNVISITED)) {
1443 0 : *locks &= ~NS_EVENT_STATE_VISITED;
1444 : }
1445 :
1446 0 : SetProperty(nsGkAtoms::lockedStyleStates, locks, nsEventStatesPropertyDtor);
1447 0 : SetHasLockedStyleStates();
1448 :
1449 0 : NotifyStyleStateChange(aStates);
1450 0 : }
1451 :
1452 : void
1453 0 : Element::UnlockStyleStates(nsEventStates aStates)
1454 : {
1455 0 : nsEventStates *locks = new nsEventStates(LockedStyleStates());
1456 :
1457 0 : *locks &= ~aStates;
1458 :
1459 0 : if (locks->IsEmpty()) {
1460 0 : DeleteProperty(nsGkAtoms::lockedStyleStates);
1461 0 : ClearHasLockedStyleStates();
1462 : delete locks;
1463 : }
1464 : else {
1465 0 : SetProperty(nsGkAtoms::lockedStyleStates, locks, nsEventStatesPropertyDtor);
1466 : }
1467 :
1468 0 : NotifyStyleStateChange(aStates);
1469 0 : }
1470 :
1471 : void
1472 0 : Element::ClearStyleStateLocks()
1473 : {
1474 0 : nsEventStates locks = LockedStyleStates();
1475 :
1476 0 : DeleteProperty(nsGkAtoms::lockedStyleStates);
1477 0 : ClearHasLockedStyleStates();
1478 :
1479 0 : NotifyStyleStateChange(locks);
1480 0 : }
1481 :
1482 : nsIContent*
1483 0 : nsIContent::FindFirstNonNativeAnonymous() const
1484 : {
1485 : // This handles also nested native anonymous content.
1486 0 : for (const nsIContent *content = this; content;
1487 0 : content = content->GetBindingParent()) {
1488 0 : if (!content->IsInNativeAnonymousSubtree()) {
1489 : // Oops, this function signature allows casting const to
1490 : // non-const. (Then again, so does GetChildAt(0)->GetParent().)
1491 0 : return const_cast<nsIContent*>(content);
1492 : }
1493 : }
1494 0 : return nsnull;
1495 : }
1496 :
1497 : nsIContent*
1498 0 : nsIContent::GetFlattenedTreeParent() const
1499 : {
1500 0 : nsIContent *parent = GetParent();
1501 0 : if (parent && parent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
1502 0 : nsIDocument *doc = parent->OwnerDoc();
1503 : nsIContent* insertionElement =
1504 0 : doc->BindingManager()->GetNestedInsertionPoint(parent, this);
1505 0 : if (insertionElement) {
1506 0 : parent = insertionElement;
1507 : }
1508 : }
1509 0 : return parent;
1510 : }
1511 :
1512 : nsIContent::IMEState
1513 0 : nsIContent::GetDesiredIMEState()
1514 : {
1515 0 : if (!IsEditableInternal()) {
1516 0 : return IMEState(IMEState::DISABLED);
1517 : }
1518 : // NOTE: The content for independent editors (e.g., input[type=text],
1519 : // textarea) must override this method, so, we don't need to worry about
1520 : // that here.
1521 0 : nsIContent *editableAncestor = GetEditingHost();
1522 :
1523 : // This is in another editable content, use the result of it.
1524 0 : if (editableAncestor && editableAncestor != this) {
1525 0 : return editableAncestor->GetDesiredIMEState();
1526 : }
1527 0 : nsIDocument* doc = GetCurrentDoc();
1528 0 : if (!doc) {
1529 0 : return IMEState(IMEState::DISABLED);
1530 : }
1531 0 : nsIPresShell* ps = doc->GetShell();
1532 0 : if (!ps) {
1533 0 : return IMEState(IMEState::DISABLED);
1534 : }
1535 0 : nsPresContext* pc = ps->GetPresContext();
1536 0 : if (!pc) {
1537 0 : return IMEState(IMEState::DISABLED);
1538 : }
1539 0 : nsIEditor* editor = GetHTMLEditor(pc);
1540 0 : nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(editor);
1541 0 : if (!imeEditor) {
1542 0 : return IMEState(IMEState::DISABLED);
1543 : }
1544 0 : IMEState state;
1545 0 : imeEditor->GetPreferredIMEState(&state);
1546 0 : return state;
1547 : }
1548 :
1549 : bool
1550 0 : nsIContent::HasIndependentSelection()
1551 : {
1552 0 : nsIFrame* frame = GetPrimaryFrame();
1553 0 : return (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION);
1554 : }
1555 :
1556 : nsIContent*
1557 0 : nsIContent::GetEditingHost()
1558 : {
1559 : // If this isn't editable, return NULL.
1560 0 : NS_ENSURE_TRUE(IsEditableInternal(), nsnull);
1561 :
1562 0 : nsIDocument* doc = GetCurrentDoc();
1563 0 : NS_ENSURE_TRUE(doc, nsnull);
1564 : // If this is in designMode, we should return <body>
1565 0 : if (doc->HasFlag(NODE_IS_EDITABLE)) {
1566 0 : return doc->GetBodyElement();
1567 : }
1568 :
1569 0 : nsIContent* content = this;
1570 0 : for (nsIContent* parent = GetParent();
1571 0 : parent && parent->HasFlag(NODE_IS_EDITABLE);
1572 0 : parent = content->GetParent()) {
1573 0 : content = parent;
1574 : }
1575 0 : return content;
1576 : }
1577 :
1578 : nsresult
1579 0 : nsIContent::LookupNamespaceURIInternal(const nsAString& aNamespacePrefix,
1580 : nsAString& aNamespaceURI) const
1581 : {
1582 0 : if (aNamespacePrefix.EqualsLiteral("xml")) {
1583 : // Special-case for xml prefix
1584 0 : aNamespaceURI.AssignLiteral("http://www.w3.org/XML/1998/namespace");
1585 0 : return NS_OK;
1586 : }
1587 :
1588 0 : if (aNamespacePrefix.EqualsLiteral("xmlns")) {
1589 : // Special-case for xmlns prefix
1590 0 : aNamespaceURI.AssignLiteral("http://www.w3.org/2000/xmlns/");
1591 0 : return NS_OK;
1592 : }
1593 :
1594 0 : nsCOMPtr<nsIAtom> name;
1595 0 : if (!aNamespacePrefix.IsEmpty()) {
1596 0 : name = do_GetAtom(aNamespacePrefix);
1597 0 : NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
1598 : }
1599 : else {
1600 0 : name = nsGkAtoms::xmlns;
1601 : }
1602 : // Trace up the content parent chain looking for the namespace
1603 : // declaration that declares aNamespacePrefix.
1604 0 : const nsIContent* content = this;
1605 0 : do {
1606 0 : if (content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI))
1607 0 : return NS_OK;
1608 0 : } while ((content = content->GetParent()));
1609 0 : return NS_ERROR_FAILURE;
1610 : }
1611 :
1612 : already_AddRefed<nsIURI>
1613 0 : nsIContent::GetBaseURI() const
1614 : {
1615 0 : nsIDocument* doc = OwnerDoc();
1616 : // Start with document base
1617 0 : nsCOMPtr<nsIURI> base = doc->GetDocBaseURI();
1618 :
1619 : // Collect array of xml:base attribute values up the parent chain. This
1620 : // is slightly slower for the case when there are xml:base attributes, but
1621 : // faster for the far more common case of there not being any such
1622 : // attributes.
1623 : // Also check for SVG elements which require special handling
1624 0 : nsAutoTArray<nsString, 5> baseAttrs;
1625 0 : nsString attr;
1626 0 : const nsIContent *elem = this;
1627 0 : do {
1628 : // First check for SVG specialness (why is this SVG specific?)
1629 0 : if (elem->IsSVG()) {
1630 0 : nsIContent* bindingParent = elem->GetBindingParent();
1631 0 : if (bindingParent) {
1632 : nsXBLBinding* binding =
1633 0 : bindingParent->OwnerDoc()->BindingManager()->GetBinding(bindingParent);
1634 0 : if (binding) {
1635 : // XXX sXBL/XBL2 issue
1636 : // If this is an anonymous XBL element use the binding
1637 : // document for the base URI.
1638 : // XXX Will fail with xml:base
1639 0 : base = binding->PrototypeBinding()->DocURI();
1640 0 : break;
1641 : }
1642 : }
1643 : }
1644 :
1645 0 : nsIURI* explicitBaseURI = elem->GetExplicitBaseURI();
1646 0 : if (explicitBaseURI) {
1647 0 : base = explicitBaseURI;
1648 0 : break;
1649 : }
1650 :
1651 : // Otherwise check for xml:base attribute
1652 0 : elem->GetAttr(kNameSpaceID_XML, nsGkAtoms::base, attr);
1653 0 : if (!attr.IsEmpty()) {
1654 0 : baseAttrs.AppendElement(attr);
1655 : }
1656 0 : elem = elem->GetParent();
1657 : } while(elem);
1658 :
1659 : // Now resolve against all xml:base attrs
1660 0 : for (PRUint32 i = baseAttrs.Length() - 1; i != PRUint32(-1); --i) {
1661 0 : nsCOMPtr<nsIURI> newBase;
1662 0 : nsresult rv = NS_NewURI(getter_AddRefs(newBase), baseAttrs[i],
1663 0 : doc->GetDocumentCharacterSet().get(), base);
1664 : // Do a security check, almost the same as nsDocument::SetBaseURL()
1665 : // Only need to do this on the final uri
1666 0 : if (NS_SUCCEEDED(rv) && i == 0) {
1667 0 : rv = nsContentUtils::GetSecurityManager()->
1668 : CheckLoadURIWithPrincipal(NodePrincipal(), newBase,
1669 0 : nsIScriptSecurityManager::STANDARD);
1670 : }
1671 0 : if (NS_SUCCEEDED(rv)) {
1672 0 : base.swap(newBase);
1673 : }
1674 : }
1675 :
1676 0 : return base.forget();
1677 : }
1678 :
1679 : static void
1680 0 : ReleaseURI(void*, /* aObject*/
1681 : nsIAtom*, /* aPropertyName */
1682 : void* aPropertyValue,
1683 : void* /* aData */)
1684 : {
1685 0 : nsIURI* uri = static_cast<nsIURI*>(aPropertyValue);
1686 0 : NS_RELEASE(uri);
1687 0 : }
1688 :
1689 : nsresult
1690 0 : nsINode::SetExplicitBaseURI(nsIURI* aURI)
1691 : {
1692 0 : nsresult rv = SetProperty(nsGkAtoms::baseURIProperty, aURI, ReleaseURI);
1693 0 : if (NS_SUCCEEDED(rv)) {
1694 0 : SetHasExplicitBaseURI();
1695 0 : NS_ADDREF(aURI);
1696 : }
1697 0 : return rv;
1698 : }
1699 :
1700 : //----------------------------------------------------------------------
1701 :
1702 : static JSObject*
1703 95931 : GetJSObjectChild(nsWrapperCache* aCache)
1704 : {
1705 95931 : if (aCache->PreservingWrapper()) {
1706 0 : return aCache->GetWrapperPreserveColor();
1707 : }
1708 95931 : return aCache->GetExpandoObjectPreserveColor();
1709 : }
1710 :
1711 : static bool
1712 36539 : NeedsScriptTraverse(nsWrapperCache* aCache)
1713 : {
1714 36539 : JSObject* o = GetJSObjectChild(aCache);
1715 36539 : return o && xpc_IsGrayGCThing(o);
1716 : }
1717 :
1718 : //----------------------------------------------------------------------
1719 :
1720 22937 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList)
1721 24464 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList)
1722 :
1723 : // If nsChildContentList is changed so that any additional fields are
1724 : // traversed by the cycle collector, then CAN_SKIP must be updated.
1725 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsChildContentList)
1726 1527 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsChildContentList)
1727 1527 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1728 1527 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1729 1527 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsChildContentList)
1730 1527 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
1731 1527 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1732 1527 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsChildContentList)
1733 1527 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
1734 1527 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
1735 :
1736 : // nsChildContentList only ever has a single child, its wrapper, so if
1737 : // the wrapper is black, the list can't be part of a garbage cycle.
1738 1063 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsChildContentList)
1739 1063 : return !NeedsScriptTraverse(tmp);
1740 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1741 :
1742 727 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsChildContentList)
1743 727 : return !NeedsScriptTraverse(tmp);
1744 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1745 :
1746 : // CanSkipThis returns false to avoid problems with incomplete unlinking.
1747 1527 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsChildContentList)
1748 1527 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1749 :
1750 42157 : NS_INTERFACE_TABLE_HEAD(nsChildContentList)
1751 42157 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1752 : NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsChildContentList)
1753 : NS_INTERFACE_TABLE_ENTRY(nsChildContentList, nsINodeList)
1754 : NS_INTERFACE_TABLE_ENTRY(nsChildContentList, nsIDOMNodeList)
1755 40630 : NS_OFFSET_AND_INTERFACE_TABLE_END
1756 40630 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1757 26863 : NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsChildContentList)
1758 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeList)
1759 0 : NS_INTERFACE_MAP_END
1760 :
1761 : JSObject*
1762 1527 : nsChildContentList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
1763 : bool *triedToWrap)
1764 : {
1765 1527 : return mozilla::dom::binding::NodeList::create(cx, scope, this, triedToWrap);
1766 : }
1767 :
1768 : NS_IMETHODIMP
1769 5684 : nsChildContentList::GetLength(PRUint32* aLength)
1770 : {
1771 5684 : *aLength = mNode ? mNode->GetChildCount() : 0;
1772 :
1773 5684 : return NS_OK;
1774 : }
1775 :
1776 : NS_IMETHODIMP
1777 0 : nsChildContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
1778 : {
1779 0 : nsINode* node = GetNodeAt(aIndex);
1780 0 : if (!node) {
1781 0 : *aReturn = nsnull;
1782 :
1783 0 : return NS_OK;
1784 : }
1785 :
1786 0 : return CallQueryInterface(node, aReturn);
1787 : }
1788 :
1789 : nsIContent*
1790 4224 : nsChildContentList::GetNodeAt(PRUint32 aIndex)
1791 : {
1792 4224 : if (mNode) {
1793 4224 : return mNode->GetChildAt(aIndex);
1794 : }
1795 :
1796 0 : return nsnull;
1797 : }
1798 :
1799 : PRInt32
1800 0 : nsChildContentList::IndexOf(nsIContent* aContent)
1801 : {
1802 0 : if (mNode) {
1803 0 : return mNode->IndexOf(aContent);
1804 : }
1805 :
1806 0 : return -1;
1807 : }
1808 :
1809 : //----------------------------------------------------------------------
1810 :
1811 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsNode3Tearoff, mNode)
1812 :
1813 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNode3Tearoff)
1814 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMXPathNSResolver)
1815 0 : NS_INTERFACE_MAP_END_AGGREGATED(mNode)
1816 :
1817 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNode3Tearoff)
1818 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNode3Tearoff)
1819 :
1820 : NS_IMETHODIMP
1821 0 : nsNode3Tearoff::LookupNamespaceURI(const nsAString& aNamespacePrefix,
1822 : nsAString& aNamespaceURI)
1823 : {
1824 0 : return mNode->LookupNamespaceURI(aNamespacePrefix, aNamespaceURI);
1825 : }
1826 :
1827 : nsIContent*
1828 4 : nsGenericElement::GetFirstElementChild()
1829 : {
1830 4 : nsAttrAndChildArray& children = mAttrsAndChildren;
1831 4 : PRUint32 i, count = children.ChildCount();
1832 8 : for (i = 0; i < count; ++i) {
1833 8 : nsIContent* child = children.ChildAt(i);
1834 8 : if (child->IsElement()) {
1835 4 : return child;
1836 : }
1837 : }
1838 :
1839 0 : return nsnull;
1840 : }
1841 :
1842 : nsIContent*
1843 0 : nsGenericElement::GetLastElementChild()
1844 : {
1845 0 : nsAttrAndChildArray& children = mAttrsAndChildren;
1846 0 : PRUint32 i = children.ChildCount();
1847 0 : while (i > 0) {
1848 0 : nsIContent* child = children.ChildAt(--i);
1849 0 : if (child->IsElement()) {
1850 0 : return child;
1851 : }
1852 : }
1853 :
1854 0 : return nsnull;
1855 : }
1856 :
1857 : nsIContent*
1858 0 : nsGenericElement::GetPreviousElementSibling()
1859 : {
1860 0 : nsIContent* parent = GetParent();
1861 0 : if (!parent) {
1862 0 : return nsnull;
1863 : }
1864 :
1865 0 : NS_ASSERTION(parent->IsElement() ||
1866 : parent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT),
1867 : "Parent content must be an element or a doc fragment");
1868 :
1869 : nsAttrAndChildArray& children =
1870 0 : static_cast<nsGenericElement*>(parent)->mAttrsAndChildren;
1871 0 : PRInt32 index = children.IndexOfChild(this);
1872 0 : if (index < 0) {
1873 0 : return nsnull;
1874 : }
1875 :
1876 0 : PRUint32 i = index;
1877 0 : while (i > 0) {
1878 0 : nsIContent* child = children.ChildAt((PRUint32)--i);
1879 0 : if (child->IsElement()) {
1880 0 : return child;
1881 : }
1882 : }
1883 :
1884 0 : return nsnull;
1885 : }
1886 :
1887 : nsIContent*
1888 0 : nsGenericElement::GetNextElementSibling()
1889 : {
1890 0 : nsIContent* parent = GetParent();
1891 0 : if (!parent) {
1892 0 : return nsnull;
1893 : }
1894 :
1895 0 : NS_ASSERTION(parent->IsElement() ||
1896 : parent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT),
1897 : "Parent content must be an element or a doc fragment");
1898 :
1899 : nsAttrAndChildArray& children =
1900 0 : static_cast<nsGenericElement*>(parent)->mAttrsAndChildren;
1901 0 : PRInt32 index = children.IndexOfChild(this);
1902 0 : if (index < 0) {
1903 0 : return nsnull;
1904 : }
1905 :
1906 0 : PRUint32 i, count = children.ChildCount();
1907 0 : for (i = (PRUint32)index + 1; i < count; ++i) {
1908 0 : nsIContent* child = children.ChildAt(i);
1909 0 : if (child->IsElement()) {
1910 0 : return child;
1911 : }
1912 : }
1913 :
1914 0 : return nsnull;
1915 : }
1916 :
1917 : NS_IMETHODIMP
1918 2 : nsNSElementTearoff::GetFirstElementChild(nsIDOMElement** aResult)
1919 : {
1920 2 : *aResult = nsnull;
1921 :
1922 2 : nsIContent *result = mContent->GetFirstElementChild();
1923 :
1924 2 : return result ? CallQueryInterface(result, aResult) : NS_OK;
1925 : }
1926 :
1927 : NS_IMETHODIMP
1928 0 : nsNSElementTearoff::GetLastElementChild(nsIDOMElement** aResult)
1929 : {
1930 0 : *aResult = nsnull;
1931 :
1932 0 : nsIContent *result = mContent->GetLastElementChild();
1933 :
1934 0 : return result ? CallQueryInterface(result, aResult) : NS_OK;
1935 : }
1936 :
1937 : NS_IMETHODIMP
1938 0 : nsNSElementTearoff::GetPreviousElementSibling(nsIDOMElement** aResult)
1939 : {
1940 0 : *aResult = nsnull;
1941 :
1942 0 : nsIContent *result = mContent->GetPreviousElementSibling();
1943 :
1944 0 : return result ? CallQueryInterface(result, aResult) : NS_OK;
1945 : }
1946 :
1947 : NS_IMETHODIMP
1948 0 : nsNSElementTearoff::GetNextElementSibling(nsIDOMElement** aResult)
1949 : {
1950 0 : *aResult = nsnull;
1951 :
1952 0 : nsIContent *result = mContent->GetNextElementSibling();
1953 :
1954 0 : return result ? CallQueryInterface(result, aResult) : NS_OK;
1955 : }
1956 :
1957 : nsContentList*
1958 167 : nsGenericElement::GetChildrenList()
1959 : {
1960 167 : nsGenericElement::nsDOMSlots *slots = DOMSlots();
1961 :
1962 167 : if (!slots->mChildrenList) {
1963 : slots->mChildrenList = new nsContentList(this, kNameSpaceID_Wildcard,
1964 : nsGkAtoms::_asterix, nsGkAtoms::_asterix,
1965 75 : false);
1966 : }
1967 :
1968 167 : return slots->mChildrenList;
1969 : }
1970 :
1971 : NS_IMETHODIMP
1972 0 : nsNSElementTearoff::GetChildElementCount(PRUint32* aResult)
1973 : {
1974 0 : return mContent->GetChildElementCount(aResult);
1975 : }
1976 :
1977 : NS_IMETHODIMP
1978 0 : nsNSElementTearoff::GetChildren(nsIDOMNodeList** aResult)
1979 : {
1980 0 : return mContent->GetChildren(aResult);
1981 : }
1982 :
1983 : nsDOMTokenList*
1984 0 : nsGenericElement::GetClassList(nsresult *aResult)
1985 : {
1986 0 : *aResult = NS_ERROR_OUT_OF_MEMORY;
1987 :
1988 0 : nsGenericElement::nsDOMSlots *slots = DOMSlots();
1989 :
1990 0 : if (!slots->mClassList) {
1991 0 : nsCOMPtr<nsIAtom> classAttr = GetClassAttributeName();
1992 0 : if (!classAttr) {
1993 0 : *aResult = NS_OK;
1994 :
1995 0 : return nsnull;
1996 : }
1997 :
1998 0 : slots->mClassList = new nsDOMTokenList(this, classAttr);
1999 0 : NS_ENSURE_TRUE(slots->mClassList, nsnull);
2000 : }
2001 :
2002 0 : *aResult = NS_OK;
2003 :
2004 0 : return slots->mClassList;
2005 : }
2006 :
2007 : NS_IMETHODIMP
2008 0 : nsNSElementTearoff::GetClassList(nsIDOMDOMTokenList** aResult)
2009 : {
2010 0 : *aResult = nsnull;
2011 :
2012 : nsresult rv;
2013 0 : nsIDOMDOMTokenList* list = mContent->GetClassList(&rv);
2014 0 : NS_ENSURE_TRUE(list, rv);
2015 :
2016 0 : NS_ADDREF(*aResult = list);
2017 :
2018 0 : return NS_OK;
2019 : }
2020 :
2021 : void
2022 0 : nsGenericElement::SetCapture(bool aRetargetToElement)
2023 : {
2024 : // If there is already an active capture, ignore this request. This would
2025 : // occur if a splitter, frame resizer, etc had already captured and we don't
2026 : // want to override those.
2027 0 : if (nsIPresShell::GetCapturingContent())
2028 0 : return;
2029 :
2030 : nsIPresShell::SetCapturingContent(this, CAPTURE_PREVENTDRAG |
2031 0 : (aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0));
2032 : }
2033 :
2034 : NS_IMETHODIMP
2035 0 : nsNSElementTearoff::SetCapture(bool aRetargetToElement)
2036 : {
2037 0 : mContent->SetCapture(aRetargetToElement);
2038 :
2039 0 : return NS_OK;
2040 : }
2041 :
2042 : void
2043 0 : nsGenericElement::ReleaseCapture()
2044 : {
2045 0 : if (nsIPresShell::GetCapturingContent() == this) {
2046 0 : nsIPresShell::SetCapturingContent(nsnull, 0);
2047 : }
2048 0 : }
2049 :
2050 : NS_IMETHODIMP
2051 0 : nsNSElementTearoff::ReleaseCapture()
2052 : {
2053 0 : mContent->ReleaseCapture();
2054 :
2055 0 : return NS_OK;
2056 : }
2057 :
2058 : //----------------------------------------------------------------------
2059 :
2060 :
2061 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsNSElementTearoff, mContent)
2062 :
2063 4 : NS_INTERFACE_MAP_BEGIN(nsNSElementTearoff)
2064 4 : NS_INTERFACE_MAP_ENTRY(nsIDOMNSElement)
2065 2 : NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsNSElementTearoff)
2066 0 : NS_INTERFACE_MAP_END_AGGREGATED(mContent)
2067 :
2068 4 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNSElementTearoff)
2069 6 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNSElementTearoff)
2070 :
2071 : NS_IMETHODIMP
2072 0 : nsNSElementTearoff::GetElementsByClassName(const nsAString& aClasses,
2073 : nsIDOMNodeList** aReturn)
2074 : {
2075 0 : return mContent->GetElementsByClassName(aClasses, aReturn);
2076 : }
2077 :
2078 : nsIFrame*
2079 0 : nsGenericElement::GetStyledFrame()
2080 : {
2081 0 : nsIFrame *frame = GetPrimaryFrame(Flush_Layout);
2082 0 : return frame ? nsLayoutUtils::GetStyleFrame(frame) : nsnull;
2083 : }
2084 :
2085 : void
2086 0 : nsGenericElement::GetOffsetRect(nsRect& aRect, nsIContent** aOffsetParent)
2087 : {
2088 0 : *aOffsetParent = nsnull;
2089 0 : aRect = nsRect();
2090 :
2091 0 : nsIFrame* frame = GetStyledFrame();
2092 0 : if (!frame) {
2093 0 : return;
2094 : }
2095 :
2096 0 : nsPoint origin = frame->GetPosition();
2097 0 : aRect.x = nsPresContext::AppUnitsToIntCSSPixels(origin.x);
2098 0 : aRect.y = nsPresContext::AppUnitsToIntCSSPixels(origin.y);
2099 :
2100 : // Get the union of all rectangles in this and continuation frames.
2101 : // It doesn't really matter what we use as aRelativeTo here, since
2102 : // we only care about the size. Using 'parent' might make things
2103 : // a bit faster by speeding up the internal GetOffsetTo operations.
2104 0 : nsIFrame* parent = frame->GetParent() ? frame->GetParent() : frame;
2105 0 : nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, parent);
2106 0 : aRect.width = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width);
2107 0 : aRect.height = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height);
2108 : }
2109 :
2110 : nsIScrollableFrame*
2111 0 : nsGenericElement::GetScrollFrame(nsIFrame **aStyledFrame)
2112 : {
2113 : // it isn't clear what to return for SVG nodes, so just return nothing
2114 0 : if (IsSVG()) {
2115 0 : if (aStyledFrame) {
2116 0 : *aStyledFrame = nsnull;
2117 : }
2118 0 : return nsnull;
2119 : }
2120 :
2121 0 : nsIFrame* frame = GetStyledFrame();
2122 :
2123 0 : if (aStyledFrame) {
2124 0 : *aStyledFrame = frame;
2125 : }
2126 0 : if (!frame) {
2127 0 : return nsnull;
2128 : }
2129 :
2130 : // menu frames implement GetScrollTargetFrame but we don't want
2131 : // to use it here. Similar for comboboxes.
2132 0 : if (frame->GetType() != nsGkAtoms::menuFrame &&
2133 0 : frame->GetType() != nsGkAtoms::comboboxControlFrame) {
2134 0 : nsIScrollableFrame *scrollFrame = frame->GetScrollTargetFrame();
2135 0 : if (scrollFrame)
2136 0 : return scrollFrame;
2137 : }
2138 :
2139 0 : nsIDocument* doc = OwnerDoc();
2140 0 : bool quirksMode = doc->GetCompatibilityMode() == eCompatibility_NavQuirks;
2141 : Element* elementWithRootScrollInfo =
2142 0 : quirksMode ? doc->GetBodyElement() : doc->GetRootElement();
2143 0 : if (this == elementWithRootScrollInfo) {
2144 : // In quirks mode, the scroll info for the body element should map to the
2145 : // root scrollable frame.
2146 : // In strict mode, the scroll info for the root element should map to the
2147 : // the root scrollable frame.
2148 0 : return frame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
2149 : }
2150 :
2151 0 : return nsnull;
2152 : }
2153 :
2154 : PRInt32
2155 0 : nsGenericElement::GetScrollTop()
2156 : {
2157 0 : nsIScrollableFrame* sf = GetScrollFrame();
2158 :
2159 : return sf ?
2160 0 : nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().y) :
2161 0 : 0;
2162 : }
2163 :
2164 : NS_IMETHODIMP
2165 0 : nsNSElementTearoff::GetScrollTop(PRInt32* aScrollTop)
2166 : {
2167 0 : *aScrollTop = mContent->GetScrollTop();
2168 :
2169 0 : return NS_OK;
2170 : }
2171 :
2172 : void
2173 0 : nsGenericElement::SetScrollTop(PRInt32 aScrollTop)
2174 : {
2175 0 : nsIScrollableFrame* sf = GetScrollFrame();
2176 0 : if (sf) {
2177 0 : nsPoint pt = sf->GetScrollPosition();
2178 0 : pt.y = nsPresContext::CSSPixelsToAppUnits(aScrollTop);
2179 0 : sf->ScrollTo(pt, nsIScrollableFrame::INSTANT);
2180 : }
2181 0 : }
2182 :
2183 : NS_IMETHODIMP
2184 0 : nsNSElementTearoff::SetScrollTop(PRInt32 aScrollTop)
2185 : {
2186 0 : mContent->SetScrollTop(aScrollTop);
2187 :
2188 0 : return NS_OK;
2189 : }
2190 :
2191 : PRInt32
2192 0 : nsGenericElement::GetScrollLeft()
2193 : {
2194 0 : nsIScrollableFrame* sf = GetScrollFrame();
2195 :
2196 : return sf ?
2197 0 : nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().x) :
2198 0 : 0;
2199 : }
2200 :
2201 : NS_IMETHODIMP
2202 0 : nsNSElementTearoff::GetScrollLeft(PRInt32* aScrollLeft)
2203 : {
2204 0 : *aScrollLeft = mContent->GetScrollLeft();
2205 :
2206 0 : return NS_OK;
2207 : }
2208 :
2209 : void
2210 0 : nsGenericElement::SetScrollLeft(PRInt32 aScrollLeft)
2211 : {
2212 0 : nsIScrollableFrame* sf = GetScrollFrame();
2213 0 : if (sf) {
2214 0 : nsPoint pt = sf->GetScrollPosition();
2215 0 : pt.x = nsPresContext::CSSPixelsToAppUnits(aScrollLeft);
2216 0 : sf->ScrollTo(pt, nsIScrollableFrame::INSTANT);
2217 : }
2218 0 : }
2219 :
2220 : NS_IMETHODIMP
2221 0 : nsNSElementTearoff::SetScrollLeft(PRInt32 aScrollLeft)
2222 : {
2223 0 : mContent->SetScrollLeft(aScrollLeft);
2224 :
2225 0 : return NS_OK;
2226 : }
2227 :
2228 : PRInt32
2229 0 : nsGenericElement::GetScrollHeight()
2230 : {
2231 0 : if (IsSVG())
2232 0 : return 0;
2233 :
2234 0 : nsIScrollableFrame* sf = GetScrollFrame();
2235 0 : if (!sf) {
2236 0 : nsRect rcFrame;
2237 0 : nsCOMPtr<nsIContent> parent;
2238 0 : GetOffsetRect(rcFrame, getter_AddRefs(parent));
2239 0 : return rcFrame.height;
2240 : }
2241 :
2242 0 : nscoord height = sf->GetScrollRange().height + sf->GetScrollPortRect().height;
2243 0 : return nsPresContext::AppUnitsToIntCSSPixels(height);
2244 : }
2245 :
2246 : NS_IMETHODIMP
2247 0 : nsNSElementTearoff::GetScrollHeight(PRInt32* aScrollHeight)
2248 : {
2249 0 : *aScrollHeight = mContent->GetScrollHeight();
2250 :
2251 0 : return NS_OK;
2252 : }
2253 :
2254 : PRInt32
2255 0 : nsGenericElement::GetScrollWidth()
2256 : {
2257 0 : if (IsSVG())
2258 0 : return 0;
2259 :
2260 0 : nsIScrollableFrame* sf = GetScrollFrame();
2261 0 : if (!sf) {
2262 0 : nsRect rcFrame;
2263 0 : nsCOMPtr<nsIContent> parent;
2264 0 : GetOffsetRect(rcFrame, getter_AddRefs(parent));
2265 0 : return rcFrame.width;
2266 : }
2267 :
2268 0 : nscoord width = sf->GetScrollRange().width + sf->GetScrollPortRect().width;
2269 0 : return nsPresContext::AppUnitsToIntCSSPixels(width);
2270 : }
2271 :
2272 : NS_IMETHODIMP
2273 0 : nsNSElementTearoff::GetScrollWidth(PRInt32 *aScrollWidth)
2274 : {
2275 0 : *aScrollWidth = mContent->GetScrollWidth();
2276 :
2277 0 : return NS_OK;
2278 : }
2279 :
2280 : nsRect
2281 0 : nsGenericElement::GetClientAreaRect()
2282 : {
2283 : nsIFrame* styledFrame;
2284 0 : nsIScrollableFrame* sf = GetScrollFrame(&styledFrame);
2285 :
2286 0 : if (sf) {
2287 0 : return sf->GetScrollPortRect();
2288 : }
2289 :
2290 0 : if (styledFrame &&
2291 0 : (styledFrame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE ||
2292 0 : styledFrame->IsFrameOfType(nsIFrame::eReplaced))) {
2293 : // Special case code to make client area work even when there isn't
2294 : // a scroll view, see bug 180552, bug 227567.
2295 0 : return styledFrame->GetPaddingRect() - styledFrame->GetPositionIgnoringScrolling();
2296 : }
2297 :
2298 : // SVG nodes reach here and just return 0
2299 0 : return nsRect(0, 0, 0, 0);
2300 : }
2301 :
2302 : NS_IMETHODIMP
2303 0 : nsNSElementTearoff::GetClientTop(PRInt32 *aClientTop)
2304 : {
2305 0 : *aClientTop = mContent->GetClientTop();
2306 0 : return NS_OK;
2307 : }
2308 :
2309 : NS_IMETHODIMP
2310 0 : nsNSElementTearoff::GetClientLeft(PRInt32 *aClientLeft)
2311 : {
2312 0 : *aClientLeft = mContent->GetClientLeft();
2313 0 : return NS_OK;
2314 : }
2315 :
2316 : NS_IMETHODIMP
2317 0 : nsNSElementTearoff::GetClientHeight(PRInt32 *aClientHeight)
2318 : {
2319 0 : *aClientHeight = mContent->GetClientHeight();
2320 0 : return NS_OK;
2321 : }
2322 :
2323 : NS_IMETHODIMP
2324 0 : nsNSElementTearoff::GetClientWidth(PRInt32 *aClientWidth)
2325 : {
2326 0 : *aClientWidth = mContent->GetClientWidth();
2327 0 : return NS_OK;
2328 : }
2329 :
2330 : nsresult
2331 0 : nsGenericElement::GetBoundingClientRect(nsIDOMClientRect** aResult)
2332 : {
2333 : // Weak ref, since we addref it below
2334 0 : nsClientRect* rect = new nsClientRect();
2335 0 : if (!rect)
2336 0 : return NS_ERROR_OUT_OF_MEMORY;
2337 :
2338 0 : NS_ADDREF(*aResult = rect);
2339 :
2340 0 : nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
2341 0 : if (!frame) {
2342 : // display:none, perhaps? Return the empty rect
2343 0 : return NS_OK;
2344 : }
2345 :
2346 : nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame,
2347 : nsLayoutUtils::GetContainingBlockForClientRect(frame),
2348 0 : nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
2349 0 : rect->SetLayoutRect(r);
2350 0 : return NS_OK;
2351 : }
2352 :
2353 : NS_IMETHODIMP
2354 0 : nsNSElementTearoff::GetBoundingClientRect(nsIDOMClientRect** aResult)
2355 : {
2356 0 : return mContent->GetBoundingClientRect(aResult);
2357 : }
2358 :
2359 : nsresult
2360 0 : nsGenericElement::GetElementsByClassName(const nsAString& aClasses,
2361 : nsIDOMNodeList** aReturn)
2362 : {
2363 0 : return nsContentUtils::GetElementsByClassName(this, aClasses, aReturn);
2364 : }
2365 :
2366 : nsresult
2367 0 : nsGenericElement::GetClientRects(nsIDOMClientRectList** aResult)
2368 : {
2369 0 : *aResult = nsnull;
2370 :
2371 0 : nsRefPtr<nsClientRectList> rectList = new nsClientRectList(this);
2372 :
2373 0 : nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
2374 0 : if (!frame) {
2375 : // display:none, perhaps? Return an empty list
2376 0 : *aResult = rectList.forget().get();
2377 0 : return NS_OK;
2378 : }
2379 :
2380 0 : nsLayoutUtils::RectListBuilder builder(rectList);
2381 : nsLayoutUtils::GetAllInFlowRects(frame,
2382 : nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder,
2383 0 : nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
2384 0 : if (NS_FAILED(builder.mRV))
2385 0 : return builder.mRV;
2386 0 : *aResult = rectList.forget().get();
2387 0 : return NS_OK;
2388 : }
2389 :
2390 : NS_IMETHODIMP
2391 0 : nsNSElementTearoff::GetClientRects(nsIDOMClientRectList** aResult)
2392 : {
2393 0 : return mContent->GetClientRects(aResult);
2394 : }
2395 :
2396 : //----------------------------------------------------------------------
2397 :
2398 :
2399 233 : NS_IMPL_ISUPPORTS1(nsNodeWeakReference,
2400 : nsIWeakReference)
2401 :
2402 23 : nsNodeWeakReference::~nsNodeWeakReference()
2403 : {
2404 23 : if (mNode) {
2405 23 : NS_ASSERTION(mNode->GetSlots() &&
2406 : mNode->GetSlots()->mWeakReference == this,
2407 : "Weak reference has wrong value");
2408 23 : mNode->GetSlots()->mWeakReference = nsnull;
2409 : }
2410 23 : }
2411 :
2412 : NS_IMETHODIMP
2413 0 : nsNodeWeakReference::QueryReferent(const nsIID& aIID, void** aInstancePtr)
2414 : {
2415 0 : return mNode ? mNode->QueryInterface(aIID, aInstancePtr) :
2416 0 : NS_ERROR_NULL_POINTER;
2417 : }
2418 :
2419 :
2420 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsNodeSupportsWeakRefTearoff, mNode)
2421 :
2422 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeSupportsWeakRefTearoff)
2423 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
2424 0 : NS_INTERFACE_MAP_END_AGGREGATED(mNode)
2425 :
2426 42 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeSupportsWeakRefTearoff)
2427 84 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeSupportsWeakRefTearoff)
2428 :
2429 : NS_IMETHODIMP
2430 42 : nsNodeSupportsWeakRefTearoff::GetWeakReference(nsIWeakReference** aInstancePtr)
2431 : {
2432 42 : nsINode::nsSlots* slots = mNode->GetSlots();
2433 42 : NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
2434 :
2435 42 : if (!slots->mWeakReference) {
2436 46 : slots->mWeakReference = new nsNodeWeakReference(mNode);
2437 23 : NS_ENSURE_TRUE(slots->mWeakReference, NS_ERROR_OUT_OF_MEMORY);
2438 : }
2439 :
2440 42 : NS_ADDREF(*aInstancePtr = slots->mWeakReference);
2441 :
2442 42 : return NS_OK;
2443 : }
2444 :
2445 : //----------------------------------------------------------------------
2446 :
2447 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsNodeSelectorTearoff, mNode)
2448 :
2449 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeSelectorTearoff)
2450 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMNodeSelector)
2451 0 : NS_INTERFACE_MAP_END_AGGREGATED(mNode)
2452 :
2453 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeSelectorTearoff)
2454 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeSelectorTearoff)
2455 :
2456 : NS_IMETHODIMP
2457 0 : nsNodeSelectorTearoff::QuerySelector(const nsAString& aSelector,
2458 : nsIDOMElement **aReturn)
2459 : {
2460 : nsresult rv;
2461 0 : nsIContent* result = nsGenericElement::doQuerySelector(mNode, aSelector, &rv);
2462 0 : return result ? CallQueryInterface(result, aReturn) : rv;
2463 : }
2464 :
2465 : NS_IMETHODIMP
2466 0 : nsNodeSelectorTearoff::QuerySelectorAll(const nsAString& aSelector,
2467 : nsIDOMNodeList **aReturn)
2468 : {
2469 0 : return nsGenericElement::doQuerySelectorAll(mNode, aSelector, aReturn);
2470 : }
2471 :
2472 : //----------------------------------------------------------------------
2473 :
2474 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsTouchEventReceiverTearoff, mElement)
2475 :
2476 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTouchEventReceiverTearoff)
2477 0 : NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver)
2478 0 : NS_INTERFACE_MAP_END_AGGREGATED(mElement)
2479 :
2480 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTouchEventReceiverTearoff)
2481 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTouchEventReceiverTearoff)
2482 :
2483 : //----------------------------------------------------------------------
2484 :
2485 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsInlineEventHandlersTearoff, mElement)
2486 :
2487 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsInlineEventHandlersTearoff)
2488 0 : NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
2489 0 : NS_INTERFACE_MAP_END_AGGREGATED(mElement)
2490 :
2491 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsInlineEventHandlersTearoff)
2492 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsInlineEventHandlersTearoff)
2493 :
2494 : //----------------------------------------------------------------------
2495 3315 : nsGenericElement::nsDOMSlots::nsDOMSlots()
2496 : : nsINode::nsSlots(),
2497 : mDataset(nsnull),
2498 3315 : mBindingParent(nsnull)
2499 : {
2500 3315 : }
2501 :
2502 9936 : nsGenericElement::nsDOMSlots::~nsDOMSlots()
2503 : {
2504 3315 : if (mAttributeMap) {
2505 0 : mAttributeMap->DropReference();
2506 : }
2507 :
2508 3315 : if (mClassList) {
2509 0 : mClassList->DropReference();
2510 : }
2511 13242 : }
2512 :
2513 : void
2514 3503 : nsGenericElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL)
2515 : {
2516 3503 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle");
2517 3503 : cb.NoteXPCOMChild(mStyle.get());
2518 :
2519 3503 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mSMILOverrideStyle");
2520 3503 : cb.NoteXPCOMChild(mSMILOverrideStyle.get());
2521 :
2522 3503 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap");
2523 3503 : cb.NoteXPCOMChild(mAttributeMap.get());
2524 :
2525 3503 : if (aIsXUL) {
2526 9 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mControllers");
2527 9 : cb.NoteXPCOMChild(mControllers);
2528 : }
2529 :
2530 3503 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
2531 3503 : cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
2532 :
2533 3503 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
2534 3503 : cb.NoteXPCOMChild(mClassList.get());
2535 3503 : }
2536 :
2537 : void
2538 3315 : nsGenericElement::nsDOMSlots::Unlink(bool aIsXUL)
2539 : {
2540 3315 : mStyle = nsnull;
2541 3315 : mSMILOverrideStyle = nsnull;
2542 3315 : if (mAttributeMap) {
2543 232 : mAttributeMap->DropReference();
2544 232 : mAttributeMap = nsnull;
2545 : }
2546 3315 : if (aIsXUL)
2547 9 : NS_IF_RELEASE(mControllers);
2548 3315 : mChildrenList = nsnull;
2549 3315 : if (mClassList) {
2550 0 : mClassList->DropReference();
2551 0 : mClassList = nsnull;
2552 : }
2553 3315 : }
2554 :
2555 38033 : nsGenericElement::nsGenericElement(already_AddRefed<nsINodeInfo> aNodeInfo)
2556 38033 : : Element(aNodeInfo)
2557 : {
2558 38033 : NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::ELEMENT_NODE ||
2559 : (mNodeInfo->NodeType() ==
2560 : nsIDOMNode::DOCUMENT_FRAGMENT_NODE &&
2561 : mNodeInfo->Equals(nsGkAtoms::documentFragmentNodeName,
2562 : kNameSpaceID_None)),
2563 : "Bad NodeType in aNodeInfo");
2564 :
2565 : // Set the default scriptID to JS - but skip SetScriptTypeID as it
2566 : // does extra work we know isn't necessary here...
2567 38033 : SetFlags((nsIProgrammingLanguage::JAVASCRIPT << NODE_SCRIPT_TYPE_OFFSET));
2568 38033 : SetIsElement();
2569 38033 : }
2570 :
2571 76062 : nsGenericElement::~nsGenericElement()
2572 : {
2573 38031 : NS_PRECONDITION(!IsInDoc(),
2574 : "Please remove this from the document properly");
2575 38031 : if (GetParent()) {
2576 0 : NS_RELEASE(mParent);
2577 : }
2578 76062 : }
2579 :
2580 : NS_IMETHODIMP
2581 127 : nsGenericElement::GetNodeName(nsAString& aNodeName)
2582 : {
2583 127 : aNodeName = NodeName();
2584 127 : return NS_OK;
2585 : }
2586 :
2587 : NS_IMETHODIMP
2588 4187 : nsGenericElement::GetLocalName(nsAString& aLocalName)
2589 : {
2590 4187 : aLocalName = LocalName();
2591 4187 : return NS_OK;
2592 : }
2593 :
2594 : NS_IMETHODIMP
2595 0 : nsGenericElement::GetNodeValue(nsAString& aNodeValue)
2596 : {
2597 0 : SetDOMStringToNull(aNodeValue);
2598 :
2599 0 : return NS_OK;
2600 : }
2601 :
2602 : NS_IMETHODIMP
2603 0 : nsGenericElement::SetNodeValue(const nsAString& aNodeValue)
2604 : {
2605 : // The DOM spec says that when nodeValue is defined to be null "setting it
2606 : // has no effect", so we don't throw an exception.
2607 0 : return NS_OK;
2608 : }
2609 :
2610 : NS_IMETHODIMP
2611 215 : nsGenericElement::GetNodeType(PRUint16* aNodeType)
2612 : {
2613 215 : *aNodeType = NodeType();
2614 215 : return NS_OK;
2615 : }
2616 :
2617 : NS_IMETHODIMP
2618 984 : nsGenericElement::GetNamespaceURI(nsAString& aNamespaceURI)
2619 : {
2620 984 : return mNodeInfo->GetNamespaceURI(aNamespaceURI);
2621 : }
2622 :
2623 : NS_IMETHODIMP
2624 0 : nsGenericElement::GetPrefix(nsAString& aPrefix)
2625 : {
2626 0 : mNodeInfo->GetPrefix(aPrefix);
2627 0 : return NS_OK;
2628 : }
2629 :
2630 : nsresult
2631 0 : nsGenericElement::InternalIsSupported(nsISupports* aObject,
2632 : const nsAString& aFeature,
2633 : const nsAString& aVersion,
2634 : bool* aReturn)
2635 : {
2636 0 : NS_ENSURE_ARG_POINTER(aReturn);
2637 0 : *aReturn = false;
2638 :
2639 : // Convert the incoming UTF16 strings to raw char*'s to save us some
2640 : // code when doing all those string compares.
2641 0 : NS_ConvertUTF16toUTF8 feature(aFeature);
2642 0 : NS_ConvertUTF16toUTF8 version(aVersion);
2643 :
2644 0 : const char *f = feature.get();
2645 0 : const char *v = version.get();
2646 :
2647 0 : if (PL_strcasecmp(f, "XML") == 0 ||
2648 0 : PL_strcasecmp(f, "HTML") == 0) {
2649 0 : if (aVersion.IsEmpty() ||
2650 0 : PL_strcmp(v, "1.0") == 0 ||
2651 0 : PL_strcmp(v, "2.0") == 0) {
2652 0 : *aReturn = true;
2653 : }
2654 0 : } else if (PL_strcasecmp(f, "Views") == 0 ||
2655 0 : PL_strcasecmp(f, "StyleSheets") == 0 ||
2656 0 : PL_strcasecmp(f, "Core") == 0 ||
2657 0 : PL_strcasecmp(f, "CSS") == 0 ||
2658 0 : PL_strcasecmp(f, "CSS2") == 0 ||
2659 0 : PL_strcasecmp(f, "Events") == 0 ||
2660 0 : PL_strcasecmp(f, "UIEvents") == 0 ||
2661 0 : PL_strcasecmp(f, "MouseEvents") == 0 ||
2662 : // Non-standard!
2663 0 : PL_strcasecmp(f, "MouseScrollEvents") == 0 ||
2664 0 : PL_strcasecmp(f, "HTMLEvents") == 0 ||
2665 0 : PL_strcasecmp(f, "Range") == 0 ||
2666 0 : PL_strcasecmp(f, "XHTML") == 0) {
2667 0 : if (aVersion.IsEmpty() ||
2668 0 : PL_strcmp(v, "2.0") == 0) {
2669 0 : *aReturn = true;
2670 : }
2671 0 : } else if (PL_strcasecmp(f, "XPath") == 0) {
2672 0 : if (aVersion.IsEmpty() ||
2673 0 : PL_strcmp(v, "3.0") == 0) {
2674 0 : *aReturn = true;
2675 : }
2676 0 : } else if (PL_strcasecmp(f, "SVGEvents") == 0 ||
2677 0 : PL_strcasecmp(f, "SVGZoomEvents") == 0 ||
2678 0 : nsSVGFeatures::HasFeature(aObject, aFeature)) {
2679 0 : if (aVersion.IsEmpty() ||
2680 0 : PL_strcmp(v, "1.0") == 0 ||
2681 0 : PL_strcmp(v, "1.1") == 0) {
2682 0 : *aReturn = true;
2683 : }
2684 : }
2685 0 : else if (NS_SMILEnabled() && PL_strcasecmp(f, "TimeControl") == 0) {
2686 0 : if (aVersion.IsEmpty() || PL_strcmp(v, "1.0") == 0) {
2687 0 : *aReturn = true;
2688 : }
2689 : }
2690 :
2691 0 : return NS_OK;
2692 : }
2693 :
2694 : NS_IMETHODIMP
2695 0 : nsGenericElement::IsSupported(const nsAString& aFeature,
2696 : const nsAString& aVersion,
2697 : bool* aReturn)
2698 : {
2699 0 : return InternalIsSupported(this, aFeature, aVersion, aReturn);
2700 : }
2701 :
2702 : NS_IMETHODIMP
2703 0 : nsGenericElement::HasAttributes(bool* aReturn)
2704 : {
2705 0 : NS_ENSURE_ARG_POINTER(aReturn);
2706 :
2707 0 : *aReturn = GetAttrCount() > 0;
2708 :
2709 0 : return NS_OK;
2710 : }
2711 :
2712 : NS_IMETHODIMP
2713 1900 : nsGenericElement::GetAttributes(nsIDOMNamedNodeMap** aAttributes)
2714 : {
2715 1900 : if (!IsElement()) {
2716 0 : *aAttributes = nsnull;
2717 0 : return NS_OK;
2718 : }
2719 :
2720 1900 : nsDOMSlots *slots = DOMSlots();
2721 :
2722 1900 : if (!slots->mAttributeMap) {
2723 232 : slots->mAttributeMap = new nsDOMAttributeMap(this);
2724 232 : if (!slots->mAttributeMap->Init()) {
2725 0 : slots->mAttributeMap = nsnull;
2726 0 : return NS_ERROR_FAILURE;
2727 : }
2728 : }
2729 :
2730 1900 : NS_ADDREF(*aAttributes = slots->mAttributeMap);
2731 :
2732 1900 : return NS_OK;
2733 : }
2734 :
2735 : nsresult
2736 11 : nsGenericElement::HasChildNodes(bool* aReturn)
2737 : {
2738 11 : *aReturn = mAttrsAndChildren.ChildCount() > 0;
2739 :
2740 11 : return NS_OK;
2741 : }
2742 :
2743 : NS_IMETHODIMP
2744 433 : nsGenericElement::GetTagName(nsAString& aTagName)
2745 : {
2746 433 : aTagName = NodeName();
2747 433 : return NS_OK;
2748 : }
2749 :
2750 : nsresult
2751 3386 : nsGenericElement::GetAttribute(const nsAString& aName,
2752 : nsAString& aReturn)
2753 : {
2754 3386 : const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
2755 :
2756 3386 : if (!name) {
2757 851 : if (mNodeInfo->NamespaceID() == kNameSpaceID_XUL) {
2758 : // XXX should be SetDOMStringToNull(aReturn);
2759 : // See bug 232598
2760 0 : aReturn.Truncate();
2761 : }
2762 : else {
2763 851 : SetDOMStringToNull(aReturn);
2764 : }
2765 :
2766 851 : return NS_OK;
2767 : }
2768 :
2769 2535 : GetAttr(name->NamespaceID(), name->LocalName(), aReturn);
2770 :
2771 2535 : return NS_OK;
2772 : }
2773 :
2774 : nsresult
2775 1847 : nsGenericElement::SetAttribute(const nsAString& aName,
2776 : const nsAString& aValue)
2777 : {
2778 1847 : const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
2779 :
2780 1847 : if (!name) {
2781 1845 : nsresult rv = nsContentUtils::CheckQName(aName, false);
2782 1845 : NS_ENSURE_SUCCESS(rv, rv);
2783 :
2784 3690 : nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
2785 1845 : NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
2786 :
2787 1845 : return SetAttr(kNameSpaceID_None, nameAtom, aValue, true);
2788 : }
2789 :
2790 : return SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
2791 2 : aValue, true);
2792 : }
2793 :
2794 : nsresult
2795 0 : nsGenericElement::RemoveAttribute(const nsAString& aName)
2796 : {
2797 0 : const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
2798 :
2799 0 : if (!name) {
2800 : // If there is no canonical nsAttrName for this attribute name, then the
2801 : // attribute does not exist and we can't get its namespace ID and
2802 : // local name below, so we return early.
2803 0 : return NS_OK;
2804 : }
2805 :
2806 : // Hold a strong reference here so that the atom or nodeinfo doesn't go
2807 : // away during UnsetAttr. If it did UnsetAttr would be left with a
2808 : // dangling pointer as argument without knowing it.
2809 0 : nsAttrName tmp(*name);
2810 :
2811 0 : return UnsetAttr(name->NamespaceID(), name->LocalName(), true);
2812 : }
2813 :
2814 : nsresult
2815 0 : nsGenericElement::GetAttributeNode(const nsAString& aName,
2816 : nsIDOMAttr** aReturn)
2817 : {
2818 0 : NS_ENSURE_ARG_POINTER(aReturn);
2819 0 : *aReturn = nsnull;
2820 :
2821 0 : nsIDocument* document = OwnerDoc();
2822 0 : if (document) {
2823 0 : document->WarnOnceAbout(nsIDocument::eGetAttributeNode);
2824 : }
2825 :
2826 0 : nsCOMPtr<nsIDOMNamedNodeMap> map;
2827 0 : nsresult rv = GetAttributes(getter_AddRefs(map));
2828 0 : NS_ENSURE_SUCCESS(rv, rv);
2829 :
2830 0 : nsCOMPtr<nsIDOMNode> node;
2831 0 : rv = map->GetNamedItem(aName, getter_AddRefs(node));
2832 :
2833 0 : if (NS_SUCCEEDED(rv) && node) {
2834 0 : rv = CallQueryInterface(node, aReturn);
2835 : }
2836 :
2837 0 : return rv;
2838 : }
2839 :
2840 : nsresult
2841 2 : nsGenericElement::SetAttributeNode(nsIDOMAttr* aAttribute,
2842 : nsIDOMAttr** aReturn)
2843 : {
2844 2 : NS_ENSURE_ARG_POINTER(aReturn);
2845 2 : NS_ENSURE_ARG_POINTER(aAttribute);
2846 :
2847 2 : *aReturn = nsnull;
2848 :
2849 2 : OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNode);
2850 :
2851 4 : nsCOMPtr<nsIDOMNamedNodeMap> map;
2852 2 : nsresult rv = GetAttributes(getter_AddRefs(map));
2853 2 : NS_ENSURE_SUCCESS(rv, rv);
2854 :
2855 4 : nsCOMPtr<nsIDOMNode> returnNode;
2856 2 : rv = map->SetNamedItem(aAttribute, getter_AddRefs(returnNode));
2857 2 : NS_ENSURE_SUCCESS(rv, rv);
2858 :
2859 2 : if (returnNode) {
2860 0 : rv = CallQueryInterface(returnNode, aReturn);
2861 : }
2862 :
2863 2 : return rv;
2864 : }
2865 :
2866 : nsresult
2867 0 : nsGenericElement::RemoveAttributeNode(nsIDOMAttr* aAttribute,
2868 : nsIDOMAttr** aReturn)
2869 : {
2870 0 : NS_ENSURE_ARG_POINTER(aReturn);
2871 0 : NS_ENSURE_ARG_POINTER(aAttribute);
2872 :
2873 0 : *aReturn = nsnull;
2874 :
2875 0 : OwnerDoc()->WarnOnceAbout(nsIDocument::eRemoveAttributeNode);
2876 :
2877 0 : nsCOMPtr<nsIDOMNamedNodeMap> map;
2878 0 : nsresult rv = GetAttributes(getter_AddRefs(map));
2879 0 : NS_ENSURE_SUCCESS(rv, rv);
2880 :
2881 0 : nsAutoString name;
2882 :
2883 0 : rv = aAttribute->GetName(name);
2884 0 : if (NS_SUCCEEDED(rv)) {
2885 0 : nsCOMPtr<nsIDOMNode> node;
2886 0 : rv = map->RemoveNamedItem(name, getter_AddRefs(node));
2887 :
2888 0 : if (NS_SUCCEEDED(rv) && node) {
2889 0 : rv = CallQueryInterface(node, aReturn);
2890 : }
2891 : }
2892 :
2893 0 : return rv;
2894 : }
2895 :
2896 : nsresult
2897 3103 : nsGenericElement::GetElementsByTagName(const nsAString& aTagname,
2898 : nsIDOMNodeList** aReturn)
2899 : {
2900 : nsContentList *list = NS_GetContentList(this, kNameSpaceID_Unknown,
2901 3103 : aTagname).get();
2902 :
2903 : // transfer ref to aReturn
2904 3103 : *aReturn = list;
2905 3103 : return NS_OK;
2906 : }
2907 :
2908 : nsresult
2909 0 : nsGenericElement::GetAttributeNS(const nsAString& aNamespaceURI,
2910 : const nsAString& aLocalName,
2911 : nsAString& aReturn)
2912 : {
2913 : PRInt32 nsid =
2914 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
2915 :
2916 0 : if (nsid == kNameSpaceID_Unknown) {
2917 : // Unknown namespace means no attribute.
2918 0 : SetDOMStringToNull(aReturn);
2919 0 : return NS_OK;
2920 : }
2921 :
2922 0 : nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
2923 0 : bool hasAttr = GetAttr(nsid, name, aReturn);
2924 0 : if (!hasAttr) {
2925 0 : SetDOMStringToNull(aReturn);
2926 : }
2927 :
2928 0 : return NS_OK;
2929 : }
2930 :
2931 : nsresult
2932 26 : nsGenericElement::SetAttributeNS(const nsAString& aNamespaceURI,
2933 : const nsAString& aQualifiedName,
2934 : const nsAString& aValue)
2935 : {
2936 52 : nsCOMPtr<nsINodeInfo> ni;
2937 : nsresult rv =
2938 : nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, aQualifiedName,
2939 : mNodeInfo->NodeInfoManager(),
2940 : nsIDOMNode::ATTRIBUTE_NODE,
2941 26 : getter_AddRefs(ni));
2942 26 : NS_ENSURE_SUCCESS(rv, rv);
2943 :
2944 : return SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(),
2945 26 : aValue, true);
2946 : }
2947 :
2948 : nsresult
2949 0 : nsGenericElement::RemoveAttributeNS(const nsAString& aNamespaceURI,
2950 : const nsAString& aLocalName)
2951 : {
2952 0 : nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
2953 : PRInt32 nsid =
2954 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
2955 :
2956 0 : if (nsid == kNameSpaceID_Unknown) {
2957 : // If the namespace ID is unknown, it means there can't possibly be an
2958 : // existing attribute. We would need a known namespace ID to pass into
2959 : // UnsetAttr, so we return early if we don't have one.
2960 0 : return NS_OK;
2961 : }
2962 :
2963 0 : UnsetAttr(nsid, name, true);
2964 :
2965 0 : return NS_OK;
2966 : }
2967 :
2968 : nsresult
2969 0 : nsGenericElement::GetAttributeNodeNS(const nsAString& aNamespaceURI,
2970 : const nsAString& aLocalName,
2971 : nsIDOMAttr** aReturn)
2972 : {
2973 0 : NS_ENSURE_ARG_POINTER(aReturn);
2974 0 : *aReturn = nsnull;
2975 :
2976 0 : OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNodeNS);
2977 :
2978 0 : return GetAttributeNodeNSInternal(aNamespaceURI, aLocalName, aReturn);
2979 : }
2980 :
2981 : nsresult
2982 0 : nsGenericElement::GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
2983 : const nsAString& aLocalName,
2984 : nsIDOMAttr** aReturn)
2985 : {
2986 0 : nsCOMPtr<nsIDOMNamedNodeMap> map;
2987 0 : nsresult rv = GetAttributes(getter_AddRefs(map));
2988 0 : NS_ENSURE_SUCCESS(rv, rv);
2989 :
2990 0 : nsCOMPtr<nsIDOMNode> node;
2991 0 : rv = map->GetNamedItemNS(aNamespaceURI, aLocalName, getter_AddRefs(node));
2992 :
2993 0 : if (NS_SUCCEEDED(rv) && node) {
2994 0 : rv = CallQueryInterface(node, aReturn);
2995 : }
2996 :
2997 0 : return rv;
2998 : }
2999 :
3000 : nsresult
3001 0 : nsGenericElement::SetAttributeNodeNS(nsIDOMAttr* aNewAttr,
3002 : nsIDOMAttr** aReturn)
3003 : {
3004 0 : NS_ENSURE_ARG_POINTER(aReturn);
3005 0 : NS_ENSURE_ARG_POINTER(aNewAttr);
3006 0 : *aReturn = nsnull;
3007 :
3008 0 : OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNodeNS);
3009 :
3010 0 : nsCOMPtr<nsIDOMNamedNodeMap> map;
3011 0 : nsresult rv = GetAttributes(getter_AddRefs(map));
3012 0 : NS_ENSURE_SUCCESS(rv, rv);
3013 :
3014 0 : nsCOMPtr<nsIDOMNode> returnNode;
3015 0 : rv = map->SetNamedItemNS(aNewAttr, getter_AddRefs(returnNode));
3016 0 : NS_ENSURE_SUCCESS(rv, rv);
3017 :
3018 0 : if (returnNode) {
3019 0 : rv = CallQueryInterface(returnNode, aReturn);
3020 : }
3021 :
3022 0 : return rv;
3023 : }
3024 :
3025 : nsresult
3026 10 : nsGenericElement::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
3027 : const nsAString& aLocalName,
3028 : nsIDOMNodeList** aReturn)
3029 : {
3030 10 : PRInt32 nameSpaceId = kNameSpaceID_Wildcard;
3031 :
3032 10 : if (!aNamespaceURI.EqualsLiteral("*")) {
3033 : nsresult rv =
3034 6 : nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
3035 6 : nameSpaceId);
3036 6 : NS_ENSURE_SUCCESS(rv, rv);
3037 : }
3038 :
3039 10 : NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
3040 :
3041 10 : nsContentList *list = NS_GetContentList(this, nameSpaceId, aLocalName).get();
3042 :
3043 : // transfer ref to aReturn
3044 10 : *aReturn = list;
3045 10 : return NS_OK;
3046 : }
3047 :
3048 : nsresult
3049 2560 : nsGenericElement::HasAttribute(const nsAString& aName, bool* aReturn)
3050 : {
3051 2560 : NS_ENSURE_ARG_POINTER(aReturn);
3052 :
3053 2560 : const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
3054 2560 : *aReturn = (name != nsnull);
3055 :
3056 2560 : return NS_OK;
3057 : }
3058 :
3059 : nsresult
3060 0 : nsGenericElement::HasAttributeNS(const nsAString& aNamespaceURI,
3061 : const nsAString& aLocalName,
3062 : bool* aReturn)
3063 : {
3064 0 : NS_ENSURE_ARG_POINTER(aReturn);
3065 :
3066 : PRInt32 nsid =
3067 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
3068 :
3069 0 : if (nsid == kNameSpaceID_Unknown) {
3070 : // Unknown namespace means no attr...
3071 :
3072 0 : *aReturn = false;
3073 :
3074 0 : return NS_OK;
3075 : }
3076 :
3077 0 : nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
3078 0 : *aReturn = HasAttr(nsid, name);
3079 :
3080 0 : return NS_OK;
3081 : }
3082 :
3083 : static nsXBLBinding*
3084 0 : GetFirstBindingWithContent(nsBindingManager* aBmgr, nsIContent* aBoundElem)
3085 : {
3086 0 : nsXBLBinding* binding = aBmgr->GetBinding(aBoundElem);
3087 0 : while (binding) {
3088 0 : if (binding->GetAnonymousContent()) {
3089 0 : return binding;
3090 : }
3091 0 : binding = binding->GetBaseBinding();
3092 : }
3093 :
3094 0 : return nsnull;
3095 : }
3096 :
3097 : static nsresult
3098 0 : BindNodesInInsertPoints(nsXBLBinding* aBinding, nsIContent* aInsertParent,
3099 : nsIDocument* aDocument)
3100 : {
3101 0 : NS_PRECONDITION(aBinding && aInsertParent, "Missing arguments");
3102 :
3103 : nsresult rv;
3104 : // These should be refcounted or otherwise protectable.
3105 : nsInsertionPointList* inserts =
3106 0 : aBinding->GetExistingInsertionPointsFor(aInsertParent);
3107 0 : if (inserts) {
3108 0 : bool allowScripts = aBinding->AllowScripts();
3109 : #ifdef MOZ_XUL
3110 0 : nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(aDocument);
3111 : #endif
3112 : PRUint32 i;
3113 0 : for (i = 0; i < inserts->Length(); ++i) {
3114 : nsCOMPtr<nsIContent> insertRoot =
3115 0 : inserts->ElementAt(i)->GetDefaultContent();
3116 0 : if (insertRoot) {
3117 0 : for (nsCOMPtr<nsIContent> child = insertRoot->GetFirstChild();
3118 0 : child;
3119 0 : child = child->GetNextSibling()) {
3120 0 : rv = child->BindToTree(aDocument, aInsertParent,
3121 0 : aBinding->GetBoundElement(), allowScripts);
3122 0 : NS_ENSURE_SUCCESS(rv, rv);
3123 :
3124 : #ifdef MOZ_XUL
3125 0 : if (xulDoc) {
3126 0 : xulDoc->AddSubtreeToDocument(child);
3127 : }
3128 : #endif
3129 : }
3130 : }
3131 : }
3132 : }
3133 :
3134 0 : return NS_OK;
3135 : }
3136 :
3137 : nsresult
3138 38038 : nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
3139 : nsIContent* aBindingParent,
3140 : bool aCompileEventHandlers)
3141 : {
3142 38038 : NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
3143 38038 : NS_PRECONDITION(HasSameOwnerDoc(NODE_FROM(aParent, aDocument)),
3144 : "Must have the same owner document");
3145 38038 : NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
3146 : "aDocument must be current doc of aParent");
3147 38038 : NS_PRECONDITION(!GetCurrentDoc(), "Already have a document. Unbind first!");
3148 : // Note that as we recurse into the kids, they'll have a non-null parent. So
3149 : // only assert if our parent is _changing_ while we have a parent.
3150 38038 : NS_PRECONDITION(!GetParent() || aParent == GetParent(),
3151 : "Already have a parent. Unbind first!");
3152 38038 : NS_PRECONDITION(!GetBindingParent() ||
3153 : aBindingParent == GetBindingParent() ||
3154 : (!aBindingParent && aParent &&
3155 : aParent->GetBindingParent() == GetBindingParent()),
3156 : "Already have a binding parent. Unbind first!");
3157 38038 : NS_PRECONDITION(!aParent || !aDocument ||
3158 : !aParent->HasFlag(NODE_FORCE_XBL_BINDINGS),
3159 : "Parent in document but flagged as forcing XBL");
3160 38038 : NS_PRECONDITION(aBindingParent != this,
3161 : "Content must not be its own binding parent");
3162 38038 : NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
3163 : aBindingParent == aParent,
3164 : "Native anonymous content must have its parent as its "
3165 : "own binding parent");
3166 :
3167 38038 : if (!aBindingParent && aParent) {
3168 36755 : aBindingParent = aParent->GetBindingParent();
3169 : }
3170 :
3171 : #ifdef MOZ_XUL
3172 : // First set the binding parent
3173 38038 : nsXULElement* xulElem = nsXULElement::FromContent(this);
3174 38038 : if (xulElem) {
3175 144 : xulElem->SetXULBindingParent(aBindingParent);
3176 : }
3177 : else
3178 : #endif
3179 : {
3180 37894 : if (aBindingParent) {
3181 0 : nsDOMSlots *slots = DOMSlots();
3182 :
3183 0 : slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
3184 : }
3185 : }
3186 38038 : NS_ASSERTION(!aBindingParent || IsRootOfNativeAnonymousSubtree() ||
3187 : !HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
3188 : (aParent && aParent->IsInNativeAnonymousSubtree()),
3189 : "Trying to re-bind content from native anonymous subtree to "
3190 : "non-native anonymous parent!");
3191 38038 : if (aParent && aParent->IsInNativeAnonymousSubtree()) {
3192 0 : SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
3193 : }
3194 :
3195 38038 : bool hadForceXBL = HasFlag(NODE_FORCE_XBL_BINDINGS);
3196 :
3197 : // Now set the parent and set the "Force attach xbl" flag if needed.
3198 38038 : if (aParent) {
3199 36755 : if (!GetParent()) {
3200 36675 : NS_ADDREF(aParent);
3201 : }
3202 36755 : mParent = aParent;
3203 :
3204 36755 : if (aParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
3205 0 : SetFlags(NODE_FORCE_XBL_BINDINGS);
3206 : }
3207 : }
3208 : else {
3209 1283 : mParent = aDocument;
3210 : }
3211 38038 : SetParentIsContent(aParent);
3212 :
3213 : // XXXbz sXBL/XBL2 issue!
3214 :
3215 : // Finally, set the document
3216 38038 : if (aDocument) {
3217 : // Notify XBL- & nsIAnonymousContentCreator-generated
3218 : // anonymous content that the document is changing.
3219 : // XXXbz ordering issues here? Probably not, since ChangeDocumentFor is
3220 : // just pretty broken anyway.... Need to get it working.
3221 : // XXXbz XBL doesn't handle this (asserts), and we don't really want
3222 : // to be doing this during parsing anyway... sort this out.
3223 : // aDocument->BindingManager()->ChangeDocumentFor(this, nsnull,
3224 : // aDocument);
3225 :
3226 : // Being added to a document.
3227 37848 : SetInDocument();
3228 :
3229 : // Unset this flag since we now really are in a document.
3230 : UnsetFlags(NODE_FORCE_XBL_BINDINGS |
3231 : // And clear the lazy frame construction bits.
3232 : NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
3233 : // And the restyle bits
3234 37848 : ELEMENT_ALL_RESTYLE_FLAGS);
3235 : }
3236 :
3237 : // If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
3238 : // that also need to be told that they are moving.
3239 : nsresult rv;
3240 38038 : if (hadForceXBL) {
3241 0 : nsBindingManager* bmgr = OwnerDoc()->BindingManager();
3242 :
3243 : // First check if we have a binding...
3244 : nsXBLBinding* contBinding =
3245 0 : GetFirstBindingWithContent(bmgr, this);
3246 0 : if (contBinding) {
3247 0 : nsCOMPtr<nsIContent> anonRoot = contBinding->GetAnonymousContent();
3248 0 : bool allowScripts = contBinding->AllowScripts();
3249 0 : for (nsCOMPtr<nsIContent> child = anonRoot->GetFirstChild();
3250 0 : child;
3251 0 : child = child->GetNextSibling()) {
3252 0 : rv = child->BindToTree(aDocument, this, this, allowScripts);
3253 0 : NS_ENSURE_SUCCESS(rv, rv);
3254 : }
3255 :
3256 : // ...then check if we have content in insertion points that are
3257 : // direct children of the <content>
3258 0 : rv = BindNodesInInsertPoints(contBinding, this, aDocument);
3259 0 : NS_ENSURE_SUCCESS(rv, rv);
3260 : }
3261 :
3262 : // ...and finally check if we're in a binding where we have content in
3263 : // insertion points.
3264 0 : if (aBindingParent) {
3265 0 : nsXBLBinding* binding = bmgr->GetBinding(aBindingParent);
3266 0 : if (binding) {
3267 0 : rv = BindNodesInInsertPoints(binding, this, aDocument);
3268 0 : NS_ENSURE_SUCCESS(rv, rv);
3269 : }
3270 : }
3271 : }
3272 :
3273 38038 : UpdateEditableState(false);
3274 :
3275 : // Now recurse into our kids
3276 38125 : for (nsIContent* child = GetFirstChild(); child;
3277 87 : child = child->GetNextSibling()) {
3278 : rv = child->BindToTree(aDocument, this, aBindingParent,
3279 87 : aCompileEventHandlers);
3280 87 : NS_ENSURE_SUCCESS(rv, rv);
3281 : }
3282 :
3283 38038 : nsNodeUtils::ParentChainChanged(this);
3284 :
3285 : // XXXbz script execution during binding can trigger some of these
3286 : // postcondition asserts.... But we do want that, since things will
3287 : // generally be quite broken when that happens.
3288 38038 : NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
3289 38038 : NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
3290 38038 : NS_POSTCONDITION(aBindingParent == GetBindingParent(),
3291 : "Bound to wrong binding parent");
3292 :
3293 38038 : return NS_OK;
3294 : }
3295 :
3296 : void
3297 118643 : nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
3298 : {
3299 118643 : NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
3300 : "Shallow unbind won't clear document and binding parent on "
3301 : "kids!");
3302 : // Make sure to unbind this node before doing the kids
3303 : nsIDocument *document =
3304 118643 : HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetCurrentDoc();
3305 :
3306 118643 : if (aNullParent) {
3307 37956 : if (IsFullScreenAncestor()) {
3308 : // The element being removed is an ancestor of the full-screen element,
3309 : // exit full-screen state.
3310 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
3311 : "DOM", OwnerDoc(),
3312 : nsContentUtils::eDOM_PROPERTIES,
3313 0 : "RemovedFullScreenElement");
3314 : // Fully exit full-screen.
3315 0 : nsIDocument::ExitFullScreen(false);
3316 : }
3317 37956 : if (GetParent()) {
3318 36675 : NS_RELEASE(mParent);
3319 : } else {
3320 1281 : mParent = nsnull;
3321 : }
3322 37956 : SetParentIsContent(false);
3323 : }
3324 118643 : ClearInDocument();
3325 :
3326 118643 : if (document) {
3327 : // Notify XBL- & nsIAnonymousContentCreator-generated
3328 : // anonymous content that the document is changing.
3329 37846 : document->BindingManager()->RemovedFromDocument(this, document);
3330 :
3331 37846 : document->ClearBoxObjectFor(this);
3332 : }
3333 :
3334 : // Ensure that CSS transitions don't continue on an element at a
3335 : // different place in the tree (even if reinserted before next
3336 : // animation refresh).
3337 : // FIXME (Bug 522599): Need a test for this.
3338 118643 : if (HasFlag(NODE_HAS_PROPERTIES)) {
3339 0 : DeleteProperty(nsGkAtoms::transitionsOfBeforeProperty);
3340 0 : DeleteProperty(nsGkAtoms::transitionsOfAfterProperty);
3341 0 : DeleteProperty(nsGkAtoms::transitionsProperty);
3342 0 : DeleteProperty(nsGkAtoms::animationsOfBeforeProperty);
3343 0 : DeleteProperty(nsGkAtoms::animationsOfAfterProperty);
3344 0 : DeleteProperty(nsGkAtoms::animationsProperty);
3345 : }
3346 :
3347 : // Unset this since that's what the old code effectively did.
3348 118643 : UnsetFlags(NODE_FORCE_XBL_BINDINGS);
3349 :
3350 : #ifdef MOZ_XUL
3351 118643 : nsXULElement* xulElem = nsXULElement::FromContent(this);
3352 118643 : if (xulElem) {
3353 435 : xulElem->SetXULBindingParent(nsnull);
3354 : }
3355 : else
3356 : #endif
3357 : {
3358 118208 : nsDOMSlots *slots = GetExistingDOMSlots();
3359 118208 : if (slots) {
3360 7798 : slots->mBindingParent = nsnull;
3361 : }
3362 : }
3363 :
3364 118643 : if (aDeep) {
3365 : // Do the kids. Don't call GetChildCount() here since that'll force
3366 : // XUL to generate template children, which there is no need for since
3367 : // all we're going to do is unbind them anyway.
3368 118643 : PRUint32 i, n = mAttrsAndChildren.ChildCount();
3369 :
3370 376281 : for (i = 0; i < n; ++i) {
3371 : // Note that we pass false for aNullParent here, since we don't want
3372 : // the kids to forget us. We _do_ want them to forget their binding
3373 : // parent, though, since this only walks non-anonymous kids.
3374 257638 : mAttrsAndChildren.ChildAt(i)->UnbindFromTree(true, false);
3375 : }
3376 : }
3377 :
3378 118643 : nsNodeUtils::ParentChainChanged(this);
3379 118643 : }
3380 :
3381 : already_AddRefed<nsINodeList>
3382 0 : nsGenericElement::GetChildren(PRUint32 aFilter)
3383 : {
3384 0 : nsRefPtr<nsSimpleContentList> list = new nsSimpleContentList(this);
3385 0 : if (!list) {
3386 0 : return nsnull;
3387 : }
3388 :
3389 0 : nsIFrame *frame = GetPrimaryFrame();
3390 :
3391 : // Append :before generated content.
3392 0 : if (frame) {
3393 0 : nsIFrame *beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
3394 0 : if (beforeFrame) {
3395 0 : list->AppendElement(beforeFrame->GetContent());
3396 : }
3397 : }
3398 :
3399 : // If XBL is bound to this node then append XBL anonymous content including
3400 : // explict content altered by insertion point if we were requested for XBL
3401 : // anonymous content, otherwise append explicit content with respect to
3402 : // insertion point if any.
3403 0 : nsINodeList *childList = nsnull;
3404 :
3405 0 : nsIDocument* document = OwnerDoc();
3406 0 : if (!(aFilter & eAllButXBL)) {
3407 0 : childList = document->BindingManager()->GetXBLChildNodesFor(this);
3408 0 : if (!childList) {
3409 0 : childList = GetChildNodesList();
3410 : }
3411 :
3412 : } else {
3413 0 : childList = document->BindingManager()->GetContentListFor(this);
3414 : }
3415 :
3416 0 : if (childList) {
3417 0 : PRUint32 length = 0;
3418 0 : childList->GetLength(&length);
3419 0 : for (PRUint32 idx = 0; idx < length; idx++) {
3420 0 : nsIContent* child = childList->GetNodeAt(idx);
3421 0 : list->AppendElement(child);
3422 : }
3423 : }
3424 :
3425 0 : if (frame) {
3426 : // Append native anonymous content to the end.
3427 0 : nsIAnonymousContentCreator* creator = do_QueryFrame(frame);
3428 0 : if (creator) {
3429 0 : creator->AppendAnonymousContentTo(*list, aFilter);
3430 : }
3431 :
3432 : // Append :after generated content.
3433 0 : nsIFrame *afterFrame = nsLayoutUtils::GetAfterFrame(frame);
3434 0 : if (afterFrame) {
3435 0 : list->AppendElement(afterFrame->GetContent());
3436 : }
3437 : }
3438 :
3439 0 : nsINodeList* returnList = nsnull;
3440 0 : list.forget(&returnList);
3441 0 : return returnList;
3442 : }
3443 :
3444 : static nsIContent*
3445 0 : FindNativeAnonymousSubtreeOwner(nsIContent* aContent)
3446 : {
3447 0 : if (aContent->IsInNativeAnonymousSubtree()) {
3448 0 : bool isNativeAnon = false;
3449 0 : while (aContent && !isNativeAnon) {
3450 0 : isNativeAnon = aContent->IsRootOfNativeAnonymousSubtree();
3451 0 : aContent = aContent->GetParent();
3452 : }
3453 : }
3454 0 : return aContent;
3455 : }
3456 :
3457 : nsresult
3458 60 : nsIContent::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
3459 : {
3460 : //FIXME! Document how this event retargeting works, Bug 329124.
3461 60 : aVisitor.mCanHandle = true;
3462 60 : aVisitor.mMayHaveListenerManager = HasListenerManager();
3463 :
3464 : // Don't propagate mouseover and mouseout events when mouse is moving
3465 : // inside native anonymous content.
3466 60 : bool isAnonForEvents = IsRootOfNativeAnonymousSubtree();
3467 60 : if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
3468 : aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) &&
3469 : // Check if we should stop event propagation when event has just been
3470 : // dispatched or when we're about to propagate from
3471 : // native anonymous subtree.
3472 0 : ((this == aVisitor.mEvent->originalTarget &&
3473 0 : !IsInNativeAnonymousSubtree()) || isAnonForEvents)) {
3474 : nsCOMPtr<nsIContent> relatedTarget =
3475 : do_QueryInterface(static_cast<nsMouseEvent*>
3476 0 : (aVisitor.mEvent)->relatedTarget);
3477 0 : if (relatedTarget &&
3478 0 : relatedTarget->OwnerDoc() == OwnerDoc()) {
3479 :
3480 : // If current target is anonymous for events or we know that related
3481 : // target is descendant of an element which is anonymous for events,
3482 : // we may want to stop event propagation.
3483 : // If this is the original target, aVisitor.mRelatedTargetIsInAnon
3484 : // must be updated.
3485 0 : if (isAnonForEvents || aVisitor.mRelatedTargetIsInAnon ||
3486 0 : (aVisitor.mEvent->originalTarget == this &&
3487 : (aVisitor.mRelatedTargetIsInAnon =
3488 0 : relatedTarget->IsInNativeAnonymousSubtree()))) {
3489 0 : nsIContent* anonOwner = FindNativeAnonymousSubtreeOwner(this);
3490 0 : if (anonOwner) {
3491 : nsIContent* anonOwnerRelated =
3492 0 : FindNativeAnonymousSubtreeOwner(relatedTarget);
3493 0 : if (anonOwnerRelated) {
3494 : // Note, anonOwnerRelated may still be inside some other
3495 : // native anonymous subtree. The case where anonOwner is still
3496 : // inside native anonymous subtree will be handled when event
3497 : // propagates up in the DOM tree.
3498 0 : while (anonOwner != anonOwnerRelated &&
3499 0 : anonOwnerRelated->IsInNativeAnonymousSubtree()) {
3500 0 : anonOwnerRelated = FindNativeAnonymousSubtreeOwner(anonOwnerRelated);
3501 : }
3502 0 : if (anonOwner == anonOwnerRelated) {
3503 : #ifdef DEBUG_smaug
3504 : nsCOMPtr<nsIContent> originalTarget =
3505 : do_QueryInterface(aVisitor.mEvent->originalTarget);
3506 : nsAutoString ot, ct, rt;
3507 : if (originalTarget) {
3508 : originalTarget->Tag()->ToString(ot);
3509 : }
3510 : Tag()->ToString(ct);
3511 : relatedTarget->Tag()->ToString(rt);
3512 : printf("Stopping %s propagation:"
3513 : "\n\toriginalTarget=%s \n\tcurrentTarget=%s %s"
3514 : "\n\trelatedTarget=%s %s \n%s",
3515 : (aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH)
3516 : ? "mouseover" : "mouseout",
3517 : NS_ConvertUTF16toUTF8(ot).get(),
3518 : NS_ConvertUTF16toUTF8(ct).get(),
3519 : isAnonForEvents
3520 : ? "(is native anonymous)"
3521 : : (IsInNativeAnonymousSubtree()
3522 : ? "(is in native anonymous subtree)" : ""),
3523 : NS_ConvertUTF16toUTF8(rt).get(),
3524 : relatedTarget->IsInNativeAnonymousSubtree()
3525 : ? "(is in native anonymous subtree)" : "",
3526 : (originalTarget && relatedTarget->FindFirstNonNativeAnonymous() ==
3527 : originalTarget->FindFirstNonNativeAnonymous())
3528 : ? "" : "Wrong event propagation!?!\n");
3529 : #endif
3530 0 : aVisitor.mParentTarget = nsnull;
3531 : // Event should not propagate to non-anon content.
3532 0 : aVisitor.mCanHandle = isAnonForEvents;
3533 0 : return NS_OK;
3534 : }
3535 : }
3536 : }
3537 : }
3538 : }
3539 : }
3540 :
3541 60 : nsIContent* parent = GetParent();
3542 : // Event may need to be retargeted if this is the root of a native
3543 : // anonymous content subtree or event is dispatched somewhere inside XBL.
3544 60 : if (isAnonForEvents) {
3545 : // If a DOM event is explicitly dispatched using node.dispatchEvent(), then
3546 : // all the events are allowed even in the native anonymous content..
3547 0 : NS_ASSERTION(aVisitor.mEvent->eventStructType != NS_MUTATION_EVENT ||
3548 : aVisitor.mDOMEvent,
3549 : "Mutation event dispatched in native anonymous content!?!");
3550 0 : aVisitor.mEventTargetAtParent = parent;
3551 60 : } else if (parent && aVisitor.mOriginalTargetIsInAnon) {
3552 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->target));
3553 0 : if (content && content->GetBindingParent() == parent) {
3554 0 : aVisitor.mEventTargetAtParent = parent;
3555 : }
3556 : }
3557 :
3558 : // check for an anonymous parent
3559 : // XXX XBL2/sXBL issue
3560 60 : if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
3561 : nsIContent* insertionParent = OwnerDoc()->BindingManager()->
3562 0 : GetInsertionParent(this);
3563 0 : NS_ASSERTION(!(aVisitor.mEventTargetAtParent && insertionParent &&
3564 : aVisitor.mEventTargetAtParent != insertionParent),
3565 : "Retargeting and having insertion parent!");
3566 0 : if (insertionParent) {
3567 0 : parent = insertionParent;
3568 : }
3569 : }
3570 :
3571 60 : if (parent) {
3572 16 : aVisitor.mParentTarget = parent;
3573 : } else {
3574 44 : aVisitor.mParentTarget = GetCurrentDoc();
3575 : }
3576 60 : return NS_OK;
3577 : }
3578 :
3579 : const nsAttrValue*
3580 0 : nsGenericElement::DoGetClasses() const
3581 : {
3582 0 : NS_NOTREACHED("Shouldn't ever be called");
3583 0 : return nsnull;
3584 : }
3585 :
3586 : NS_IMETHODIMP
3587 0 : nsGenericElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
3588 : {
3589 0 : return NS_OK;
3590 : }
3591 :
3592 : nsIDOMCSSStyleDeclaration*
3593 0 : nsGenericElement::GetSMILOverrideStyle()
3594 : {
3595 0 : nsGenericElement::nsDOMSlots *slots = DOMSlots();
3596 :
3597 0 : if (!slots->mSMILOverrideStyle) {
3598 0 : slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true);
3599 : }
3600 :
3601 0 : return slots->mSMILOverrideStyle;
3602 : }
3603 :
3604 : css::StyleRule*
3605 0 : nsGenericElement::GetSMILOverrideStyleRule()
3606 : {
3607 0 : nsGenericElement::nsDOMSlots *slots = GetExistingDOMSlots();
3608 0 : return slots ? slots->mSMILOverrideStyleRule.get() : nsnull;
3609 : }
3610 :
3611 : nsresult
3612 0 : nsGenericElement::SetSMILOverrideStyleRule(css::StyleRule* aStyleRule,
3613 : bool aNotify)
3614 : {
3615 0 : nsGenericElement::nsDOMSlots *slots = DOMSlots();
3616 :
3617 0 : slots->mSMILOverrideStyleRule = aStyleRule;
3618 :
3619 0 : if (aNotify) {
3620 0 : nsIDocument* doc = GetCurrentDoc();
3621 : // Only need to request a restyle if we're in a document. (We might not
3622 : // be in a document, if we're clearing animation effects on a target node
3623 : // that's been detached since the previous animation sample.)
3624 0 : if (doc) {
3625 0 : nsCOMPtr<nsIPresShell> shell = doc->GetShell();
3626 0 : if (shell) {
3627 0 : shell->RestyleForAnimation(this, eRestyle_Self);
3628 : }
3629 : }
3630 : }
3631 :
3632 0 : return NS_OK;
3633 : }
3634 :
3635 : css::StyleRule*
3636 0 : nsGenericElement::GetInlineStyleRule()
3637 : {
3638 0 : return nsnull;
3639 : }
3640 :
3641 : NS_IMETHODIMP
3642 0 : nsGenericElement::SetInlineStyleRule(css::StyleRule* aStyleRule,
3643 : bool aNotify)
3644 : {
3645 0 : NS_NOTYETIMPLEMENTED("nsGenericElement::SetInlineStyleRule");
3646 0 : return NS_ERROR_NOT_IMPLEMENTED;
3647 : }
3648 :
3649 : NS_IMETHODIMP_(bool)
3650 9705 : nsGenericElement::IsAttributeMapped(const nsIAtom* aAttribute) const
3651 : {
3652 9705 : return false;
3653 : }
3654 :
3655 : nsChangeHint
3656 0 : nsGenericElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
3657 : PRInt32 aModType) const
3658 : {
3659 0 : return nsChangeHint(0);
3660 : }
3661 :
3662 : nsIAtom *
3663 0 : nsGenericElement::GetClassAttributeName() const
3664 : {
3665 0 : return nsnull;
3666 : }
3667 :
3668 : bool
3669 0 : nsGenericElement::FindAttributeDependence(const nsIAtom* aAttribute,
3670 : const MappedAttributeEntry* const aMaps[],
3671 : PRUint32 aMapCount)
3672 : {
3673 0 : for (PRUint32 mapindex = 0; mapindex < aMapCount; ++mapindex) {
3674 0 : for (const MappedAttributeEntry* map = aMaps[mapindex];
3675 : map->attribute; ++map) {
3676 0 : if (aAttribute == *map->attribute) {
3677 0 : return true;
3678 : }
3679 : }
3680 : }
3681 :
3682 0 : return false;
3683 : }
3684 :
3685 : already_AddRefed<nsINodeInfo>
3686 2 : nsGenericElement::GetExistingAttrNameFromQName(const nsAString& aStr) const
3687 : {
3688 2 : const nsAttrName* name = InternalGetExistingAttrNameFromQName(aStr);
3689 2 : if (!name) {
3690 2 : return nsnull;
3691 : }
3692 :
3693 : nsINodeInfo* nodeInfo;
3694 0 : if (name->IsAtom()) {
3695 : nodeInfo = mNodeInfo->NodeInfoManager()->
3696 : GetNodeInfo(name->Atom(), nsnull, kNameSpaceID_None,
3697 0 : nsIDOMNode::ATTRIBUTE_NODE).get();
3698 : }
3699 : else {
3700 0 : NS_ADDREF(nodeInfo = name->NodeInfo());
3701 : }
3702 :
3703 0 : return nodeInfo;
3704 : }
3705 :
3706 : bool
3707 0 : nsGenericElement::IsLink(nsIURI** aURI) const
3708 : {
3709 0 : *aURI = nsnull;
3710 0 : return false;
3711 : }
3712 :
3713 : // static
3714 : bool
3715 0 : nsGenericElement::ShouldBlur(nsIContent *aContent)
3716 : {
3717 : // Determine if the current element is focused, if it is not focused
3718 : // then we should not try to blur
3719 0 : nsIDocument *document = aContent->GetDocument();
3720 0 : if (!document)
3721 0 : return false;
3722 :
3723 0 : nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(document->GetWindow());
3724 0 : if (!window)
3725 0 : return false;
3726 :
3727 0 : nsCOMPtr<nsPIDOMWindow> focusedFrame;
3728 : nsIContent* contentToBlur =
3729 0 : nsFocusManager::GetFocusedDescendant(window, false, getter_AddRefs(focusedFrame));
3730 0 : if (contentToBlur == aContent)
3731 0 : return true;
3732 :
3733 : // if focus on this element would get redirected, then check the redirected
3734 : // content as well when blurring.
3735 0 : return (contentToBlur && nsFocusManager::GetRedirectedFocus(aContent) == contentToBlur);
3736 : }
3737 :
3738 : nsIContent*
3739 234926 : nsGenericElement::GetBindingParent() const
3740 : {
3741 234926 : nsDOMSlots *slots = GetExistingDOMSlots();
3742 :
3743 234926 : if (slots) {
3744 249 : return slots->mBindingParent;
3745 : }
3746 234677 : return nsnull;
3747 : }
3748 :
3749 : bool
3750 273164 : nsGenericElement::IsNodeOfType(PRUint32 aFlags) const
3751 : {
3752 273164 : return !(aFlags & ~eCONTENT);
3753 : }
3754 :
3755 : //----------------------------------------------------------------------
3756 :
3757 : PRUint32
3758 0 : nsGenericElement::GetScriptTypeID() const
3759 : {
3760 0 : PtrBits flags = GetFlags();
3761 :
3762 0 : return (flags >> NODE_SCRIPT_TYPE_OFFSET) & NODE_SCRIPT_TYPE_MASK;
3763 : }
3764 :
3765 : NS_IMETHODIMP
3766 0 : nsGenericElement::SetScriptTypeID(PRUint32 aLang)
3767 : {
3768 0 : if ((aLang & NODE_SCRIPT_TYPE_MASK) != aLang) {
3769 0 : NS_ERROR("script ID too large!");
3770 0 : return NS_ERROR_FAILURE;
3771 : }
3772 : /* SetFlags will just mask in the specific flags set, leaving existing
3773 : ones alone. So we must clear all the bits first */
3774 0 : UnsetFlags(NODE_SCRIPT_TYPE_MASK << NODE_SCRIPT_TYPE_OFFSET);
3775 0 : SetFlags(aLang << NODE_SCRIPT_TYPE_OFFSET);
3776 0 : return NS_OK;
3777 : }
3778 :
3779 : nsresult
3780 110572 : nsGenericElement::InsertChildAt(nsIContent* aKid,
3781 : PRUint32 aIndex,
3782 : bool aNotify)
3783 : {
3784 110572 : NS_PRECONDITION(aKid, "null ptr");
3785 :
3786 110572 : return doInsertChildAt(aKid, aIndex, aNotify, mAttrsAndChildren);
3787 : }
3788 :
3789 : static nsresult
3790 0 : AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode)
3791 : {
3792 0 : NS_ASSERTION(!aNode->GetNodeParent(),
3793 : "Should have removed from parent already");
3794 :
3795 0 : nsIDocument *doc = aParent->OwnerDoc();
3796 :
3797 : nsresult rv;
3798 0 : nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc, &rv);
3799 0 : NS_ENSURE_SUCCESS(rv, rv);
3800 :
3801 0 : nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode, &rv);
3802 0 : NS_ENSURE_SUCCESS(rv, rv);
3803 :
3804 0 : nsCOMPtr<nsIDOMNode> adoptedNode;
3805 0 : rv = domDoc->AdoptNode(node, getter_AddRefs(adoptedNode));
3806 0 : NS_ENSURE_SUCCESS(rv, rv);
3807 :
3808 0 : NS_ASSERTION(aParent->OwnerDoc() == doc,
3809 : "ownerDoc chainged while adopting");
3810 0 : NS_ASSERTION(adoptedNode == node, "Uh, adopt node changed nodes?");
3811 0 : NS_ASSERTION(aParent->HasSameOwnerDoc(aNode),
3812 : "ownerDocument changed again after adopting!");
3813 :
3814 0 : return NS_OK;
3815 : }
3816 :
3817 : nsresult
3818 111957 : nsINode::doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
3819 : bool aNotify, nsAttrAndChildArray& aChildArray)
3820 : {
3821 111957 : NS_PRECONDITION(!aKid->GetNodeParent(),
3822 : "Inserting node that already has parent");
3823 : nsresult rv;
3824 :
3825 : // The id-handling code, and in the future possibly other code, need to
3826 : // react to unexpected attribute changes.
3827 111957 : nsMutationGuard::DidMutate();
3828 :
3829 : // Do this before checking the child-count since this could cause mutations
3830 111957 : nsIDocument* doc = GetCurrentDoc();
3831 223914 : mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
3832 :
3833 111957 : if (!HasSameOwnerDoc(aKid)) {
3834 0 : rv = AdoptNodeIntoOwnerDoc(this, aKid);
3835 0 : NS_ENSURE_SUCCESS(rv, rv);
3836 : }
3837 :
3838 111957 : PRUint32 childCount = aChildArray.ChildCount();
3839 111957 : NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE);
3840 111957 : bool isAppend = (aIndex == childCount);
3841 :
3842 111957 : rv = aChildArray.InsertChildAt(aKid, aIndex);
3843 111957 : NS_ENSURE_SUCCESS(rv, rv);
3844 111957 : if (aIndex == 0) {
3845 37132 : mFirstChild = aKid;
3846 : }
3847 :
3848 : nsIContent* parent =
3849 111957 : IsNodeOfType(eDOCUMENT) ? nsnull : static_cast<nsIContent*>(this);
3850 :
3851 111957 : rv = aKid->BindToTree(doc, parent, nsnull, true);
3852 111957 : if (NS_FAILED(rv)) {
3853 0 : if (GetFirstChild() == aKid) {
3854 0 : mFirstChild = aKid->GetNextSibling();
3855 : }
3856 0 : aChildArray.RemoveChildAt(aIndex);
3857 0 : aKid->UnbindFromTree();
3858 0 : return rv;
3859 : }
3860 :
3861 111957 : NS_ASSERTION(aKid->GetNodeParent() == this,
3862 : "Did we run script inappropriately?");
3863 :
3864 111957 : if (aNotify) {
3865 : // Note that we always want to call ContentInserted when things are added
3866 : // as kids to documents
3867 1470 : if (parent && isAppend) {
3868 409 : nsNodeUtils::ContentAppended(parent, aKid, aIndex);
3869 : } else {
3870 1061 : nsNodeUtils::ContentInserted(this, aKid, aIndex);
3871 : }
3872 :
3873 1470 : if (nsContentUtils::HasMutationListeners(aKid,
3874 1470 : NS_EVENT_BITS_MUTATION_NODEINSERTED, this)) {
3875 4 : nsMutationEvent mutation(true, NS_MUTATION_NODEINSERTED);
3876 2 : mutation.mRelatedNode = do_QueryInterface(this);
3877 :
3878 4 : mozAutoSubtreeModified subtree(OwnerDoc(), this);
3879 2 : (new nsAsyncDOMEvent(aKid, mutation))->RunDOMEventWhenSafe();
3880 : }
3881 : }
3882 :
3883 111957 : return NS_OK;
3884 : }
3885 :
3886 : nsresult
3887 229 : nsGenericElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
3888 : {
3889 458 : nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
3890 229 : NS_ASSERTION(oldKid == GetChildAt(aIndex), "Unexpected child in RemoveChildAt");
3891 :
3892 229 : if (oldKid) {
3893 229 : return doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren);
3894 : }
3895 :
3896 0 : return NS_OK;
3897 : }
3898 :
3899 : nsresult
3900 239 : nsINode::doRemoveChildAt(PRUint32 aIndex, bool aNotify,
3901 : nsIContent* aKid, nsAttrAndChildArray& aChildArray)
3902 : {
3903 239 : NS_PRECONDITION(aKid && aKid->GetNodeParent() == this &&
3904 : aKid == GetChildAt(aIndex) &&
3905 : IndexOf(aKid) == (PRInt32)aIndex, "Bogus aKid");
3906 :
3907 239 : nsMutationGuard::DidMutate();
3908 :
3909 239 : nsIDocument* doc = GetCurrentDoc();
3910 :
3911 478 : mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
3912 :
3913 239 : nsIContent* previousSibling = aKid->GetPreviousSibling();
3914 :
3915 239 : if (GetFirstChild() == aKid) {
3916 119 : mFirstChild = aKid->GetNextSibling();
3917 : }
3918 :
3919 239 : aChildArray.RemoveChildAt(aIndex);
3920 :
3921 239 : if (aNotify) {
3922 239 : nsNodeUtils::ContentRemoved(this, aKid, aIndex, previousSibling);
3923 : }
3924 :
3925 239 : aKid->UnbindFromTree();
3926 :
3927 239 : return NS_OK;
3928 : }
3929 :
3930 : NS_IMETHODIMP
3931 3875 : nsGenericElement::GetTextContent(nsAString &aTextContent)
3932 : {
3933 3875 : nsContentUtils::GetNodeTextContent(this, true, aTextContent);
3934 3875 : return NS_OK;
3935 : }
3936 :
3937 : NS_IMETHODIMP
3938 1 : nsGenericElement::SetTextContent(const nsAString& aTextContent)
3939 : {
3940 1 : return nsContentUtils::SetNodeTextContent(this, aTextContent, false);
3941 : }
3942 :
3943 : /* static */
3944 : nsresult
3945 0 : nsGenericElement::DispatchEvent(nsPresContext* aPresContext,
3946 : nsEvent* aEvent,
3947 : nsIContent* aTarget,
3948 : bool aFullDispatch,
3949 : nsEventStatus* aStatus)
3950 : {
3951 0 : NS_PRECONDITION(aTarget, "Must have target");
3952 0 : NS_PRECONDITION(aEvent, "Must have source event");
3953 0 : NS_PRECONDITION(aStatus, "Null out param?");
3954 :
3955 0 : if (!aPresContext) {
3956 0 : return NS_OK;
3957 : }
3958 :
3959 0 : nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
3960 0 : if (!shell) {
3961 0 : return NS_OK;
3962 : }
3963 :
3964 0 : if (aFullDispatch) {
3965 0 : return shell->HandleEventWithTarget(aEvent, nsnull, aTarget, aStatus);
3966 : }
3967 :
3968 0 : return shell->HandleDOMEventWithTarget(aTarget, aEvent, aStatus);
3969 : }
3970 :
3971 : /* static */
3972 : nsresult
3973 0 : nsGenericElement::DispatchClickEvent(nsPresContext* aPresContext,
3974 : nsInputEvent* aSourceEvent,
3975 : nsIContent* aTarget,
3976 : bool aFullDispatch,
3977 : PRUint32 aFlags,
3978 : nsEventStatus* aStatus)
3979 : {
3980 0 : NS_PRECONDITION(aTarget, "Must have target");
3981 0 : NS_PRECONDITION(aSourceEvent, "Must have source event");
3982 0 : NS_PRECONDITION(aStatus, "Null out param?");
3983 :
3984 : nsMouseEvent event(NS_IS_TRUSTED_EVENT(aSourceEvent), NS_MOUSE_CLICK,
3985 0 : aSourceEvent->widget, nsMouseEvent::eReal);
3986 0 : event.refPoint = aSourceEvent->refPoint;
3987 0 : PRUint32 clickCount = 1;
3988 0 : float pressure = 0;
3989 0 : PRUint16 inputSource = 0;
3990 0 : if (aSourceEvent->eventStructType == NS_MOUSE_EVENT) {
3991 0 : clickCount = static_cast<nsMouseEvent*>(aSourceEvent)->clickCount;
3992 0 : pressure = static_cast<nsMouseEvent*>(aSourceEvent)->pressure;
3993 0 : inputSource = static_cast<nsMouseEvent*>(aSourceEvent)->inputSource;
3994 0 : } else if (aSourceEvent->eventStructType == NS_KEY_EVENT) {
3995 0 : inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
3996 : }
3997 0 : event.pressure = pressure;
3998 0 : event.clickCount = clickCount;
3999 0 : event.inputSource = inputSource;
4000 0 : event.isShift = aSourceEvent->isShift;
4001 0 : event.isControl = aSourceEvent->isControl;
4002 0 : event.isAlt = aSourceEvent->isAlt;
4003 0 : event.isMeta = aSourceEvent->isMeta;
4004 0 : event.flags |= aFlags; // Be careful not to overwrite existing flags!
4005 :
4006 0 : return DispatchEvent(aPresContext, &event, aTarget, aFullDispatch, aStatus);
4007 : }
4008 :
4009 : nsIFrame*
4010 0 : nsGenericElement::GetPrimaryFrame(mozFlushType aType)
4011 : {
4012 0 : nsIDocument* doc = GetCurrentDoc();
4013 0 : if (!doc) {
4014 0 : return nsnull;
4015 : }
4016 :
4017 : // Cause a flush, so we get up-to-date frame
4018 : // information
4019 0 : doc->FlushPendingNotifications(aType);
4020 :
4021 0 : return GetPrimaryFrame();
4022 : }
4023 :
4024 : void
4025 0 : nsGenericElement::DestroyContent()
4026 : {
4027 0 : nsIDocument *document = OwnerDoc();
4028 0 : document->BindingManager()->RemovedFromDocument(this, document);
4029 0 : document->ClearBoxObjectFor(this);
4030 :
4031 : // XXX We really should let cycle collection do this, but that currently still
4032 : // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
4033 0 : nsContentUtils::ReleaseWrapper(this, this);
4034 :
4035 0 : PRUint32 i, count = mAttrsAndChildren.ChildCount();
4036 0 : for (i = 0; i < count; ++i) {
4037 : // The child can remove itself from the parent in BindToTree.
4038 0 : mAttrsAndChildren.ChildAt(i)->DestroyContent();
4039 : }
4040 0 : }
4041 :
4042 : void
4043 0 : nsGenericElement::SaveSubtreeState()
4044 : {
4045 0 : PRUint32 i, count = mAttrsAndChildren.ChildCount();
4046 0 : for (i = 0; i < count; ++i) {
4047 0 : mAttrsAndChildren.ChildAt(i)->SaveSubtreeState();
4048 : }
4049 0 : }
4050 :
4051 : //----------------------------------------------------------------------
4052 :
4053 : // Generic DOMNode implementations
4054 :
4055 : // When replacing, aRefChild is the content being replaced; when
4056 : // inserting it's the content before which we're inserting. In the
4057 : // latter case it may be null.
4058 : static
4059 417 : bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent,
4060 : bool aIsReplace, nsINode* aRefChild)
4061 : {
4062 417 : NS_PRECONDITION(aNewChild, "Must have new child");
4063 417 : NS_PRECONDITION(!aIsReplace || aRefChild,
4064 : "Must have ref content for replace");
4065 417 : NS_PRECONDITION(aParent->IsNodeOfType(nsINode::eDOCUMENT) ||
4066 : aParent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
4067 : aParent->IsElement(),
4068 : "Nodes that are not documents, document fragments or "
4069 : "elements can't be parents!");
4070 :
4071 417 : if (aParent && nsContentUtils::ContentIsDescendantOf(aParent, aNewChild)) {
4072 0 : return false;
4073 : }
4074 :
4075 : // The allowed child nodes differ for documents and elements
4076 417 : switch (aNewChild->NodeType()) {
4077 : case nsIDOMNode::COMMENT_NODE :
4078 : case nsIDOMNode::PROCESSING_INSTRUCTION_NODE :
4079 : // OK in both cases
4080 30 : return true;
4081 : case nsIDOMNode::TEXT_NODE :
4082 : case nsIDOMNode::CDATA_SECTION_NODE :
4083 : case nsIDOMNode::ENTITY_REFERENCE_NODE :
4084 : // Only allowed under elements
4085 103 : return aParent != nsnull;
4086 : case nsIDOMNode::ELEMENT_NODE :
4087 : {
4088 284 : if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
4089 : // Always ok to have elements under other elements or document fragments
4090 283 : return true;
4091 : }
4092 :
4093 : Element* rootElement =
4094 1 : static_cast<nsIDocument*>(aParent)->GetRootElement();
4095 1 : if (rootElement) {
4096 : // Already have a documentElement, so this is only OK if we're
4097 : // replacing it.
4098 0 : return aIsReplace && rootElement == aRefChild;
4099 : }
4100 :
4101 : // We don't have a documentElement yet. Our one remaining constraint is
4102 : // that the documentElement must come after the doctype.
4103 1 : if (!aRefChild) {
4104 : // Appending is just fine.
4105 1 : return true;
4106 : }
4107 :
4108 : // Now grovel for a doctype
4109 0 : nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aParent);
4110 0 : NS_ASSERTION(doc, "Shouldn't happen");
4111 0 : nsCOMPtr<nsIDOMDocumentType> docType;
4112 0 : doc->GetDoctype(getter_AddRefs(docType));
4113 0 : nsCOMPtr<nsIContent> docTypeContent = do_QueryInterface(docType);
4114 :
4115 0 : if (!docTypeContent) {
4116 : // It's all good.
4117 0 : return true;
4118 : }
4119 :
4120 0 : PRInt32 doctypeIndex = aParent->IndexOf(docTypeContent);
4121 0 : PRInt32 insertIndex = aParent->IndexOf(aRefChild);
4122 :
4123 : // Now we're OK in the following two cases only:
4124 : // 1) We're replacing something that's not before the doctype
4125 : // 2) We're inserting before something that comes after the doctype
4126 : return aIsReplace ? (insertIndex >= doctypeIndex) :
4127 0 : insertIndex > doctypeIndex;
4128 : }
4129 : case nsIDOMNode::DOCUMENT_TYPE_NODE :
4130 : {
4131 0 : if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
4132 : // doctypes only allowed under documents
4133 0 : return false;
4134 : }
4135 :
4136 0 : nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aParent);
4137 0 : NS_ASSERTION(doc, "Shouldn't happen");
4138 0 : nsCOMPtr<nsIDOMDocumentType> docType;
4139 0 : doc->GetDoctype(getter_AddRefs(docType));
4140 0 : nsCOMPtr<nsIContent> docTypeContent = do_QueryInterface(docType);
4141 0 : if (docTypeContent) {
4142 : // Already have a doctype, so this is only OK if we're replacing it
4143 0 : return aIsReplace && docTypeContent == aRefChild;
4144 : }
4145 :
4146 : // We don't have a doctype yet. Our one remaining constraint is
4147 : // that the doctype must come before the documentElement.
4148 : Element* rootElement =
4149 0 : static_cast<nsIDocument*>(aParent)->GetRootElement();
4150 0 : if (!rootElement) {
4151 : // It's all good
4152 0 : return true;
4153 : }
4154 :
4155 0 : if (!aRefChild) {
4156 : // Trying to append a doctype, but have a documentElement
4157 0 : return false;
4158 : }
4159 :
4160 0 : PRInt32 rootIndex = aParent->IndexOf(rootElement);
4161 0 : PRInt32 insertIndex = aParent->IndexOf(aRefChild);
4162 :
4163 : // Now we're OK if and only if insertIndex <= rootIndex. Indeed, either
4164 : // we end up replacing aRefChild or we end up before it. Either one is
4165 : // ok as long as aRefChild is not after rootElement.
4166 0 : return insertIndex <= rootIndex;
4167 : }
4168 : case nsIDOMNode::DOCUMENT_FRAGMENT_NODE :
4169 : {
4170 : // Note that for now we only allow nodes inside document fragments if
4171 : // they're allowed inside elements. If we ever change this to allow
4172 : // doctype nodes in document fragments, we'll need to update this code
4173 0 : if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
4174 : // All good here
4175 0 : return true;
4176 : }
4177 :
4178 0 : bool sawElement = false;
4179 0 : for (nsIContent* child = aNewChild->GetFirstChild();
4180 : child;
4181 0 : child = child->GetNextSibling()) {
4182 0 : if (child->IsElement()) {
4183 0 : if (sawElement) {
4184 : // Can't put two elements into a document
4185 0 : return false;
4186 : }
4187 0 : sawElement = true;
4188 : }
4189 : // If we can put this content at the the right place, we might be ok;
4190 : // if not, we bail out.
4191 0 : if (!IsAllowedAsChild(child, aParent, aIsReplace, aRefChild)) {
4192 0 : return false;
4193 : }
4194 : }
4195 :
4196 : // Everything in the fragment checked out ok, so we can stick it in here
4197 0 : return true;
4198 : }
4199 : default:
4200 : /*
4201 : * aNewChild is of invalid type.
4202 : */
4203 : break;
4204 : }
4205 :
4206 0 : return false;
4207 : }
4208 :
4209 : void
4210 0 : nsGenericElement::FireNodeInserted(nsIDocument* aDoc,
4211 : nsINode* aParent,
4212 : nsTArray<nsCOMPtr<nsIContent> >& aNodes)
4213 : {
4214 0 : PRUint32 count = aNodes.Length();
4215 0 : for (PRUint32 i = 0; i < count; ++i) {
4216 0 : nsIContent* childContent = aNodes[i];
4217 :
4218 0 : if (nsContentUtils::HasMutationListeners(childContent,
4219 0 : NS_EVENT_BITS_MUTATION_NODEINSERTED, aParent)) {
4220 0 : nsMutationEvent mutation(true, NS_MUTATION_NODEINSERTED);
4221 0 : mutation.mRelatedNode = do_QueryInterface(aParent);
4222 :
4223 0 : mozAutoSubtreeModified subtree(aDoc, aParent);
4224 0 : (new nsAsyncDOMEvent(childContent, mutation))->RunDOMEventWhenSafe();
4225 : }
4226 : }
4227 0 : }
4228 :
4229 : nsresult
4230 417 : nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
4231 : nsINode* aRefChild)
4232 : {
4233 417 : if (!aNewChild || (aReplace && !aRefChild)) {
4234 0 : return NS_ERROR_NULL_POINTER;
4235 : }
4236 :
4237 1521 : if ((!IsNodeOfType(eDOCUMENT) &&
4238 416 : !IsNodeOfType(eDOCUMENT_FRAGMENT) &&
4239 271 : !IsElement()) ||
4240 417 : !aNewChild->IsNodeOfType(eCONTENT)){
4241 0 : return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
4242 : }
4243 :
4244 417 : PRUint16 nodeType = aNewChild->NodeType();
4245 :
4246 : // Before we do anything else, fire all DOMNodeRemoved mutation events
4247 : // We do this up front as to avoid having to deal with script running
4248 : // at random places further down.
4249 : // Scope firing mutation events so that we don't carry any state that
4250 : // might be stale
4251 : {
4252 : // This check happens again further down (though then using IndexOf).
4253 : // We're only checking this here to avoid firing mutation events when
4254 : // none should be fired.
4255 : // It's ok that we do the check twice in the case when firing mutation
4256 : // events as we need to recheck after running script anyway.
4257 417 : if (aRefChild && aRefChild->GetNodeParent() != this) {
4258 0 : return NS_ERROR_DOM_NOT_FOUND_ERR;
4259 : }
4260 :
4261 : // If we're replacing, fire for node-to-be-replaced.
4262 : // If aRefChild == aNewChild then we'll fire for it in check below
4263 417 : if (aReplace && aRefChild != aNewChild) {
4264 0 : nsContentUtils::MaybeFireNodeRemoved(aRefChild, this, OwnerDoc());
4265 : }
4266 :
4267 : // If the new node already has a parent, fire for removing from old
4268 : // parent
4269 417 : nsINode* oldParent = aNewChild->GetNodeParent();
4270 417 : if (oldParent) {
4271 : nsContentUtils::MaybeFireNodeRemoved(aNewChild, oldParent,
4272 80 : aNewChild->OwnerDoc());
4273 : }
4274 :
4275 : // If we're inserting a fragment, fire for all the children of the
4276 : // fragment
4277 417 : if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
4278 0 : static_cast<nsGenericElement*>(aNewChild)->FireNodeRemovedForChildren();
4279 : }
4280 : }
4281 :
4282 417 : nsIDocument* doc = OwnerDoc();
4283 417 : nsIContent* newContent = static_cast<nsIContent*>(aNewChild);
4284 : PRInt32 insPos;
4285 :
4286 834 : mozAutoDocUpdate batch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, true);
4287 :
4288 : // Figure out which index to insert at
4289 417 : if (aRefChild) {
4290 8 : insPos = IndexOf(aRefChild);
4291 8 : if (insPos < 0) {
4292 0 : return NS_ERROR_DOM_NOT_FOUND_ERR;
4293 : }
4294 : }
4295 : else {
4296 409 : insPos = GetChildCount();
4297 : }
4298 :
4299 : // Make sure that the inserted node is allowed as a child of its new parent.
4300 417 : if (!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) {
4301 0 : return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
4302 : }
4303 :
4304 : nsresult res;
4305 :
4306 : // If we're replacing
4307 417 : if (aReplace) {
4308 0 : res = RemoveChildAt(insPos, true);
4309 0 : NS_ENSURE_SUCCESS(res, res);
4310 : }
4311 :
4312 417 : if (newContent->IsRootOfAnonymousSubtree()) {
4313 : // This is anonymous content. Don't allow its insertion
4314 : // anywhere, since it might have UnbindFromTree calls coming
4315 : // its way.
4316 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
4317 : }
4318 :
4319 : // Remove the new child from the old parent if one exists
4320 834 : nsCOMPtr<nsINode> oldParent = newContent->GetNodeParent();
4321 417 : if (oldParent) {
4322 80 : PRInt32 removeIndex = oldParent->IndexOf(newContent);
4323 80 : if (removeIndex < 0) {
4324 : // newContent is anonymous. We can't deal with this, so just bail
4325 0 : NS_ERROR("How come our flags didn't catch this?");
4326 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
4327 : }
4328 :
4329 80 : res = oldParent->RemoveChildAt(removeIndex, true);
4330 80 : NS_ENSURE_SUCCESS(res, res);
4331 :
4332 : // Adjust insert index if the node we ripped out was a sibling
4333 : // of the node we're inserting before
4334 80 : if (oldParent == this && removeIndex < insPos) {
4335 73 : --insPos;
4336 : }
4337 : }
4338 :
4339 : // Move new child over to our document if needed. Do this after removing
4340 : // it from its parent so that AdoptNode doesn't fire DOMNodeRemoved
4341 : // DocumentType nodes are the only nodes that can have a null
4342 : // ownerDocument according to the DOM spec, and we need to allow
4343 : // inserting them w/o calling AdoptNode().
4344 417 : if (!HasSameOwnerDoc(newContent)) {
4345 0 : res = AdoptNodeIntoOwnerDoc(this, aNewChild);
4346 0 : NS_ENSURE_SUCCESS(res, res);
4347 : }
4348 :
4349 : /*
4350 : * Check if we're inserting a document fragment. If we are, we need
4351 : * to remove the children of the document fragment and add them
4352 : * individually (i.e. we don't add the actual document fragment).
4353 : */
4354 417 : if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
4355 0 : PRUint32 count = newContent->GetChildCount();
4356 :
4357 0 : if (!count) {
4358 0 : return NS_OK;
4359 : }
4360 :
4361 : // Copy the children into a separate array to avoid having to deal with
4362 : // mutations to the fragment while we're inserting.
4363 0 : nsAutoTArray<nsCOMPtr<nsIContent>, 50> fragChildren;
4364 0 : fragChildren.SetCapacity(count);
4365 0 : for (nsIContent* child = newContent->GetFirstChild();
4366 : child;
4367 0 : child = child->GetNextSibling()) {
4368 0 : NS_ASSERTION(child->GetCurrentDoc() == nsnull,
4369 : "How did we get a child with a current doc?");
4370 0 : fragChildren.AppendElement(child);
4371 : }
4372 :
4373 : // Remove the children from the fragment.
4374 0 : for (PRUint32 i = count; i > 0;) {
4375 0 : newContent->RemoveChildAt(--i, true);
4376 : }
4377 :
4378 : bool appending =
4379 0 : !IsNodeOfType(eDOCUMENT) && PRUint32(insPos) == GetChildCount();
4380 0 : PRInt32 firstInsPos = insPos;
4381 0 : nsIContent* firstInsertedContent = fragChildren[0];
4382 :
4383 : // Iterate through the fragment's children, and insert them in the new
4384 : // parent
4385 0 : for (PRUint32 i = 0; i < count; ++i, ++insPos) {
4386 : // XXXbz how come no reparenting here? That seems odd...
4387 : // Insert the child.
4388 0 : res = InsertChildAt(fragChildren[i], insPos, !appending);
4389 0 : if (NS_FAILED(res)) {
4390 : // Make sure to notify on any children that we did succeed to insert
4391 0 : if (appending && i != 0) {
4392 : nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
4393 : firstInsertedContent,
4394 0 : firstInsPos);
4395 : }
4396 0 : return res;
4397 : }
4398 : }
4399 :
4400 : // Notify and fire mutation events when appending
4401 0 : if (appending) {
4402 : nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
4403 0 : firstInsertedContent, firstInsPos);
4404 : // Optimize for the case when there are no listeners
4405 0 : if (nsContentUtils::
4406 : HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
4407 0 : nsGenericElement::FireNodeInserted(doc, this, fragChildren);
4408 : }
4409 : }
4410 : }
4411 : else {
4412 : // Not inserting a fragment but rather a single node.
4413 :
4414 : // FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=544654
4415 : // We need to reparent here for nodes for which the parent of their
4416 : // wrapper is not the wrapper for their ownerDocument (XUL elements,
4417 : // form controls, ...). Also applies in the fragment code above.
4418 :
4419 417 : res = InsertChildAt(newContent, insPos, true);
4420 417 : NS_ENSURE_SUCCESS(res, res);
4421 : }
4422 :
4423 417 : return NS_OK;
4424 : }
4425 :
4426 : nsresult
4427 0 : nsINode::CompareDocumentPosition(nsIDOMNode* aOther, PRUint16* aReturn)
4428 : {
4429 0 : nsCOMPtr<nsINode> other = do_QueryInterface(aOther);
4430 0 : if (!other) {
4431 0 : return NS_ERROR_NULL_POINTER;
4432 : }
4433 0 : *aReturn = CompareDocPosition(other);
4434 0 : return NS_OK;
4435 : }
4436 :
4437 : nsresult
4438 0 : nsINode::IsEqualNode(nsIDOMNode* aOther, bool* aReturn)
4439 : {
4440 0 : nsCOMPtr<nsINode> other = do_QueryInterface(aOther);
4441 0 : *aReturn = IsEqualTo(other);
4442 0 : return NS_OK;
4443 : }
4444 :
4445 : //----------------------------------------------------------------------
4446 :
4447 : // nsISupports implementation
4448 :
4449 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericElement)
4450 :
4451 : #define SUBTREE_UNBINDINGS_PER_RUNNABLE 500
4452 :
4453 : class ContentUnbinder : public nsRunnable
4454 : {
4455 : public:
4456 21 : ContentUnbinder()
4457 21 : {
4458 21 : nsLayoutStatics::AddRef();
4459 21 : mLast = this;
4460 21 : }
4461 :
4462 42 : ~ContentUnbinder()
4463 42 : {
4464 21 : Run();
4465 21 : nsLayoutStatics::Release();
4466 84 : }
4467 :
4468 32364 : void UnbindSubtree(nsIContent* aNode)
4469 : {
4470 53982 : if (aNode->NodeType() != nsIDOMNode::ELEMENT_NODE &&
4471 21618 : aNode->NodeType() != nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
4472 21618 : return;
4473 : }
4474 10746 : nsGenericElement* container = static_cast<nsGenericElement*>(aNode);
4475 10746 : PRUint32 childCount = container->mAttrsAndChildren.ChildCount();
4476 10746 : if (childCount) {
4477 53429 : while (childCount-- > 0) {
4478 : // Hold a strong ref to the node when we remove it, because we may be
4479 : // the last reference to it. We need to call TakeChildAt() and
4480 : // update mFirstChild before calling UnbindFromTree, since this last
4481 : // can notify various observers and they should really see consistent
4482 : // tree state.
4483 : nsCOMPtr<nsIContent> child =
4484 64370 : container->mAttrsAndChildren.TakeChildAt(childCount);
4485 32185 : if (childCount == 0) {
4486 10622 : container->mFirstChild = nsnull;
4487 : }
4488 32185 : UnbindSubtree(child);
4489 32185 : child->UnbindFromTree();
4490 : }
4491 : }
4492 : }
4493 :
4494 42 : NS_IMETHOD Run()
4495 : {
4496 84 : nsAutoScriptBlocker scriptBlocker;
4497 42 : PRUint32 len = mSubtreeRoots.Length();
4498 42 : if (len) {
4499 21 : PRTime start = PR_Now();
4500 200 : for (PRUint32 i = 0; i < len; ++i) {
4501 179 : UnbindSubtree(mSubtreeRoots[i]);
4502 : }
4503 21 : mSubtreeRoots.Clear();
4504 : Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_CONTENT_UNBIND,
4505 21 : PRUint32(PR_Now() - start) / PR_USEC_PER_MSEC);
4506 : }
4507 42 : if (this == sContentUnbinder) {
4508 21 : sContentUnbinder = nsnull;
4509 21 : if (mNext) {
4510 0 : nsRefPtr<ContentUnbinder> next;
4511 0 : next.swap(mNext);
4512 0 : sContentUnbinder = next;
4513 0 : next->mLast = mLast;
4514 0 : mLast = nsnull;
4515 0 : NS_DispatchToMainThread(next);
4516 : }
4517 : }
4518 42 : return NS_OK;
4519 : }
4520 :
4521 179 : static void Append(nsIContent* aSubtreeRoot)
4522 : {
4523 179 : if (!sContentUnbinder) {
4524 21 : sContentUnbinder = new ContentUnbinder();
4525 42 : nsCOMPtr<nsIRunnable> e = sContentUnbinder;
4526 21 : NS_DispatchToMainThread(e);
4527 : }
4528 :
4529 179 : if (sContentUnbinder->mLast->mSubtreeRoots.Length() >=
4530 : SUBTREE_UNBINDINGS_PER_RUNNABLE) {
4531 0 : sContentUnbinder->mLast->mNext = new ContentUnbinder();
4532 0 : sContentUnbinder->mLast = sContentUnbinder->mLast->mNext;
4533 : }
4534 179 : sContentUnbinder->mLast->mSubtreeRoots.AppendElement(aSubtreeRoot);
4535 179 : }
4536 :
4537 : private:
4538 : nsAutoTArray<nsCOMPtr<nsIContent>,
4539 : SUBTREE_UNBINDINGS_PER_RUNNABLE> mSubtreeRoots;
4540 : nsRefPtr<ContentUnbinder> mNext;
4541 : ContentUnbinder* mLast;
4542 : static ContentUnbinder* sContentUnbinder;
4543 : };
4544 :
4545 : ContentUnbinder* ContentUnbinder::sContentUnbinder = nsnull;
4546 :
4547 37985 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement)
4548 37985 : nsINode::Unlink(tmp);
4549 :
4550 37985 : if (tmp->HasProperties() && tmp->IsXUL()) {
4551 0 : tmp->DeleteProperty(nsGkAtoms::contextmenulistener);
4552 0 : tmp->DeleteProperty(nsGkAtoms::popuplistener);
4553 : }
4554 :
4555 : // Unlink child content (and unbind our subtree).
4556 37985 : if (UnoptimizableCCNode(tmp) || !nsCCUncollectableMarker::sGeneration) {
4557 27231 : PRUint32 childCount = tmp->mAttrsAndChildren.ChildCount();
4558 27231 : if (childCount) {
4559 : // Don't allow script to run while we're unbinding everything.
4560 50282 : nsAutoScriptBlocker scriptBlocker;
4561 128438 : while (childCount-- > 0) {
4562 : // Hold a strong ref to the node when we remove it, because we may be
4563 : // the last reference to it. We need to call TakeChildAt() and
4564 : // update mFirstChild before calling UnbindFromTree, since this last
4565 : // can notify various observers and they should really see consistent
4566 : // tree state.
4567 156312 : nsCOMPtr<nsIContent> child = tmp->mAttrsAndChildren.TakeChildAt(childCount);
4568 78156 : if (childCount == 0) {
4569 25141 : tmp->mFirstChild = nsnull;
4570 : }
4571 78156 : child->UnbindFromTree();
4572 : }
4573 : }
4574 10754 : } else if (!tmp->GetParent() && tmp->mAttrsAndChildren.ChildCount()) {
4575 179 : ContentUnbinder::Append(tmp);
4576 : } /* else {
4577 : The subtree root will end up to a ContentUnbinder, and that will
4578 : unbind the child nodes.
4579 : } */
4580 :
4581 : // Unlink any DOM slots of interest.
4582 : {
4583 37985 : nsDOMSlots *slots = tmp->GetExistingDOMSlots();
4584 37985 : if (slots) {
4585 3315 : slots->Unlink(tmp->IsXUL());
4586 : }
4587 : }
4588 :
4589 : {
4590 : nsIDocument *doc;
4591 37985 : if (!tmp->GetNodeParent() && (doc = tmp->OwnerDoc())) {
4592 22127 : doc->BindingManager()->RemovedFromDocument(tmp, doc);
4593 : }
4594 : }
4595 37985 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
4596 :
4597 45891 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericElement)
4598 45891 : nsINode::Trace(tmp, aCallback, aClosure);
4599 45891 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
4600 :
4601 : void
4602 0 : nsGenericElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
4603 : void* aData)
4604 : {
4605 0 : PRUint32* gen = static_cast<PRUint32*>(aData);
4606 0 : xpc_MarkInCCGeneration(static_cast<nsISupports*>(aChild), *gen);
4607 0 : }
4608 :
4609 : void
4610 0 : nsGenericElement::MarkUserDataHandler(void* aObject, nsIAtom* aKey,
4611 : void* aChild, void* aData)
4612 : {
4613 : nsCOMPtr<nsIXPConnectWrappedJS> wjs =
4614 0 : do_QueryInterface(static_cast<nsISupports*>(aChild));
4615 0 : xpc_UnmarkGrayObject(wjs);
4616 0 : }
4617 :
4618 : void
4619 22838 : nsGenericElement::MarkNodeChildren(nsINode* aNode)
4620 : {
4621 22838 : JSObject* o = GetJSObjectChild(aNode);
4622 22838 : xpc_UnmarkGrayObject(o);
4623 :
4624 22838 : nsEventListenerManager* elm = aNode->GetListenerManager(false);
4625 22838 : if (elm) {
4626 0 : elm->UnmarkGrayJSListeners();
4627 : }
4628 :
4629 22838 : if (aNode->HasProperties()) {
4630 0 : nsIDocument* ownerDoc = aNode->OwnerDoc();
4631 : ownerDoc->PropertyTable(DOM_USER_DATA)->
4632 : Enumerate(aNode, nsGenericElement::MarkUserData,
4633 0 : &nsCCUncollectableMarker::sGeneration);
4634 : ownerDoc->PropertyTable(DOM_USER_DATA_HANDLER)->
4635 : Enumerate(aNode, nsGenericElement::MarkUserDataHandler,
4636 0 : &nsCCUncollectableMarker::sGeneration);
4637 : }
4638 22838 : }
4639 :
4640 : nsINode*
4641 1935 : FindOptimizableSubtreeRoot(nsINode* aNode)
4642 : {
4643 : nsINode* p;
4644 7470 : while ((p = aNode->GetNodeParent())) {
4645 3600 : if (UnoptimizableCCNode(aNode)) {
4646 0 : return nsnull;
4647 : }
4648 3600 : aNode = p;
4649 : }
4650 :
4651 1935 : if (UnoptimizableCCNode(aNode)) {
4652 0 : return nsnull;
4653 : }
4654 1935 : return aNode;
4655 : }
4656 :
4657 : nsAutoTArray<nsINode*, 1020>* gCCBlackMarkedNodes = nsnull;
4658 :
4659 : void
4660 1910 : ClearBlackMarkedNodes()
4661 : {
4662 1910 : if (!gCCBlackMarkedNodes) {
4663 1889 : return;
4664 : }
4665 21 : PRUint32 len = gCCBlackMarkedNodes->Length();
4666 222 : for (PRUint32 i = 0; i < len; ++i) {
4667 201 : nsINode* n = gCCBlackMarkedNodes->ElementAt(i);
4668 201 : n->SetCCMarkedRoot(false);
4669 201 : n->SetInCCBlackTree(false);
4670 : }
4671 21 : delete gCCBlackMarkedNodes;
4672 21 : gCCBlackMarkedNodes = nsnull;
4673 : }
4674 :
4675 : // static
4676 : bool
4677 97084 : nsGenericElement::CanSkipInCC(nsINode* aNode)
4678 : {
4679 : // Don't try to optimize anything during shutdown.
4680 97084 : if (nsCCUncollectableMarker::sGeneration == 0) {
4681 68968 : return false;
4682 : }
4683 :
4684 : // Bail out early if aNode is somewhere in anonymous content,
4685 : // or otherwise unusual.
4686 28116 : if (UnoptimizableCCNode(aNode)) {
4687 0 : return false;
4688 : }
4689 :
4690 28116 : nsIDocument* currentDoc = aNode->GetCurrentDoc();
4691 56232 : if (currentDoc &&
4692 28116 : nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) {
4693 1890 : return !NeedsScriptTraverse(aNode);
4694 : }
4695 :
4696 : nsINode* root =
4697 : currentDoc ? static_cast<nsINode*>(currentDoc) :
4698 26226 : FindOptimizableSubtreeRoot(aNode);
4699 26226 : if (!root) {
4700 0 : return false;
4701 : }
4702 :
4703 : // Subtree has been traversed already.
4704 26226 : if (root->CCMarkedRoot()) {
4705 26025 : return root->InCCBlackTree() && !NeedsScriptTraverse(aNode);
4706 : }
4707 :
4708 201 : if (!gCCBlackMarkedNodes) {
4709 21 : gCCBlackMarkedNodes = new nsAutoTArray<nsINode*, 1020>;
4710 : }
4711 :
4712 : // nodesToUnpurple contains nodes which will be removed
4713 : // from the purple buffer if the DOM tree is black.
4714 402 : nsAutoTArray<nsIContent*, 1020> nodesToUnpurple;
4715 : // grayNodes need script traverse, so they aren't removed from
4716 : // the purple buffer, but are marked to be in black subtree so that
4717 : // traverse is faster.
4718 402 : nsAutoTArray<nsINode*, 1020> grayNodes;
4719 :
4720 201 : bool foundBlack = root->IsBlack();
4721 201 : if (root != currentDoc) {
4722 0 : currentDoc = nsnull;
4723 0 : if (NeedsScriptTraverse(root)) {
4724 0 : grayNodes.AppendElement(root);
4725 0 : } else if (static_cast<nsIContent*>(root)->IsPurple()) {
4726 0 : nodesToUnpurple.AppendElement(static_cast<nsIContent*>(root));
4727 : }
4728 : }
4729 :
4730 : // Traverse the subtree and check if we could know without CC
4731 : // that it is black.
4732 : // Note, this traverse is non-virtual and inline, so it should be a lot faster
4733 : // than CC's generic traverse.
4734 33052 : for (nsIContent* node = root->GetFirstChild(); node;
4735 32851 : node = node->GetNextNode(root)) {
4736 32859 : foundBlack = foundBlack || node->IsBlack();
4737 32859 : if (foundBlack && currentDoc) {
4738 : // If we can mark the whole document black, no need to optimize
4739 : // so much, since when the next purple node in the document will be
4740 : // handled, it is fast to check that currentDoc is in CCGeneration.
4741 8 : break;
4742 : }
4743 32851 : if (NeedsScriptTraverse(node)) {
4744 : // Gray nodes need real CC traverse.
4745 0 : grayNodes.AppendElement(node);
4746 32851 : } else if (node->IsPurple()) {
4747 26025 : nodesToUnpurple.AppendElement(node);
4748 : }
4749 : }
4750 :
4751 201 : root->SetCCMarkedRoot(true);
4752 201 : root->SetInCCBlackTree(foundBlack);
4753 201 : gCCBlackMarkedNodes->AppendElement(root);
4754 :
4755 201 : if (!foundBlack) {
4756 193 : return false;
4757 : }
4758 :
4759 8 : if (currentDoc) {
4760 : // Special case documents. If we know the document is black,
4761 : // we can mark the document to be in CCGeneration.
4762 : currentDoc->
4763 8 : MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
4764 : } else {
4765 0 : for (PRUint32 i = 0; i < grayNodes.Length(); ++i) {
4766 0 : nsINode* node = grayNodes[i];
4767 0 : node->SetInCCBlackTree(true);
4768 : }
4769 0 : gCCBlackMarkedNodes->AppendElements(grayNodes);
4770 : }
4771 :
4772 : // Subtree is black, we can remove non-gray purple nodes from
4773 : // purple buffer.
4774 8 : for (PRUint32 i = 0; i < nodesToUnpurple.Length(); ++i) {
4775 0 : nsIContent* purple = nodesToUnpurple[i];
4776 : // Can't remove currently handled purple node.
4777 0 : if (purple != aNode) {
4778 0 : purple->RemovePurple();
4779 : }
4780 : }
4781 8 : return !NeedsScriptTraverse(aNode);
4782 : }
4783 :
4784 : nsAutoTArray<nsINode*, 1020>* gPurpleRoots = nsnull;
4785 :
4786 276 : void ClearPurpleRoots()
4787 : {
4788 276 : if (!gPurpleRoots) {
4789 56 : return;
4790 : }
4791 220 : PRUint32 len = gPurpleRoots->Length();
4792 2386 : for (PRUint32 i = 0; i < len; ++i) {
4793 2166 : nsINode* n = gPurpleRoots->ElementAt(i);
4794 2166 : n->SetIsPurpleRoot(false);
4795 : }
4796 220 : delete gPurpleRoots;
4797 220 : gPurpleRoots = nsnull;
4798 : }
4799 :
4800 : static bool
4801 285388 : ShouldClearPurple(nsIContent* aContent)
4802 : {
4803 285388 : if (aContent && aContent->IsPurple()) {
4804 248834 : return true;
4805 : }
4806 :
4807 36554 : JSObject* o = GetJSObjectChild(aContent);
4808 36554 : if (o && xpc_IsGrayGCThing(o)) {
4809 0 : return true;
4810 : }
4811 :
4812 36554 : if (aContent->HasListenerManager()) {
4813 0 : return true;
4814 : }
4815 :
4816 36554 : return aContent->HasProperties();
4817 : }
4818 :
4819 : // If aNode is not optimizable, but is an element
4820 : // with a frame in a document which has currently active presshell,
4821 : // we can act as if it was optimizable. When the primary frame dies, aNode
4822 : // will end up to the purple buffer because of the refcount change.
4823 : bool
4824 0 : NodeHasActiveFrame(nsIDocument* aCurrentDoc, nsINode* aNode)
4825 : {
4826 0 : return aCurrentDoc->GetShell() && aNode->IsElement() &&
4827 0 : aNode->AsElement()->GetPrimaryFrame();
4828 : }
4829 :
4830 : // CanSkip checks if aNode is black, and if it is, returns
4831 : // true. If aNode is in a black DOM tree, CanSkip may also remove other objects
4832 : // from purple buffer and unmark event listeners and user data.
4833 : // If the root of the DOM tree is a document, less optimizations are done
4834 : // since checking the blackness of the current document is usually fast and we
4835 : // don't want slow down such common cases.
4836 : bool
4837 318556 : nsGenericElement::CanSkip(nsINode* aNode, bool aRemovingAllowed)
4838 : {
4839 : // Don't try to optimize anything during shutdown.
4840 318556 : if (nsCCUncollectableMarker::sGeneration == 0) {
4841 579 : return false;
4842 : }
4843 :
4844 317977 : bool unoptimizable = UnoptimizableCCNode(aNode);
4845 317977 : nsIDocument* currentDoc = aNode->GetCurrentDoc();
4846 654777 : if (currentDoc &&
4847 316042 : nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration()) &&
4848 20758 : (!unoptimizable || NodeHasActiveFrame(currentDoc, aNode))) {
4849 20758 : MarkNodeChildren(aNode);
4850 20758 : return true;
4851 : }
4852 297219 : if (unoptimizable) {
4853 0 : return false;
4854 : }
4855 :
4856 : nsINode* root = currentDoc ? static_cast<nsINode*>(currentDoc) :
4857 297219 : FindOptimizableSubtreeRoot(aNode);
4858 297219 : if (!root) {
4859 0 : return false;
4860 : }
4861 :
4862 : // Subtree has been traversed already, and aNode
4863 : // wasn't removed from purple buffer. No need to do more here.
4864 297219 : if (root->IsPurpleRoot()) {
4865 294943 : return false;
4866 : }
4867 :
4868 : // nodesToClear contains nodes which are either purple or
4869 : // gray.
4870 4552 : nsAutoTArray<nsIContent*, 1020> nodesToClear;
4871 :
4872 2276 : bool foundBlack = root->IsBlack();
4873 2276 : if (root != currentDoc) {
4874 45 : currentDoc = nsnull;
4875 45 : if (ShouldClearPurple(static_cast<nsIContent*>(root))) {
4876 45 : nodesToClear.AppendElement(static_cast<nsIContent*>(root));
4877 : }
4878 : }
4879 :
4880 : // Traverse the subtree and check if we could know without CC
4881 : // that it is black.
4882 : // Note, this traverse is non-virtual and inline, so it should be a lot faster
4883 : // than CC's generic traverse.
4884 287619 : for (nsIContent* node = root->GetFirstChild(); node;
4885 285343 : node = node->GetNextNode(root)) {
4886 285453 : foundBlack = foundBlack || node->IsBlack();
4887 285453 : if (foundBlack) {
4888 110 : if (currentDoc) {
4889 : // If we can mark the whole document black, no need to optimize
4890 : // so much, since when the next purple node in the document will be
4891 : // handled, it is fast to check that the currentDoc is in CCGeneration.
4892 110 : break;
4893 : }
4894 : // No need to put stuff to the nodesToClear array, if we can clear it
4895 : // already here.
4896 0 : if (node->IsPurple() && (node != aNode || aRemovingAllowed)) {
4897 0 : node->RemovePurple();
4898 : }
4899 0 : MarkNodeChildren(node);
4900 285343 : } else if (ShouldClearPurple(node)) {
4901 : // Collect interesting nodes which we can clear if we find that
4902 : // they are kept alive in a black tree.
4903 248789 : nodesToClear.AppendElement(node);
4904 : }
4905 : }
4906 :
4907 2276 : if (!currentDoc || !foundBlack) {
4908 2166 : if (!gPurpleRoots) {
4909 220 : gPurpleRoots = new nsAutoTArray<nsINode*, 1020>();
4910 : }
4911 2166 : root->SetIsPurpleRoot(true);
4912 2166 : gPurpleRoots->AppendElement(root);
4913 : }
4914 :
4915 2276 : if (!foundBlack) {
4916 2166 : return false;
4917 : }
4918 :
4919 110 : if (currentDoc) {
4920 : // Special case documents. If we know the document is black,
4921 : // we can mark the document to be in CCGeneration.
4922 : currentDoc->
4923 110 : MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
4924 110 : MarkNodeChildren(currentDoc);
4925 : }
4926 :
4927 : // Subtree is black, so we can remove purple nodes from
4928 : // purple buffer and mark stuff that to be certainly alive.
4929 110 : for (PRUint32 i = 0; i < nodesToClear.Length(); ++i) {
4930 0 : nsIContent* n = nodesToClear[i];
4931 0 : MarkNodeChildren(n);
4932 : // Can't remove currently handled purple node,
4933 : // unless aRemovingAllowed is true.
4934 0 : if ((n != aNode || aRemovingAllowed) && n->IsPurple()) {
4935 0 : n->RemovePurple();
4936 : }
4937 : }
4938 110 : return true;
4939 : }
4940 :
4941 : bool
4942 225591 : nsGenericElement::CanSkipThis(nsINode* aNode)
4943 : {
4944 225591 : if (nsCCUncollectableMarker::sGeneration == 0) {
4945 159882 : return false;
4946 : }
4947 65709 : if (aNode->IsBlack()) {
4948 0 : return true;
4949 : }
4950 65709 : nsIDocument* c = aNode->GetCurrentDoc();
4951 : return
4952 65709 : ((c && nsCCUncollectableMarker::InGeneration(c->GetMarkedCCGeneration())) ||
4953 131418 : aNode->InCCBlackTree()) && !NeedsScriptTraverse(aNode);
4954 : }
4955 :
4956 : void
4957 1404 : nsGenericElement::InitCCCallbacks()
4958 : {
4959 1404 : nsCycleCollector_setForgetSkippableCallback(ClearPurpleRoots);
4960 1404 : nsCycleCollector_setBeforeUnlinkCallback(ClearBlackMarkedNodes);
4961 1404 : }
4962 :
4963 120993 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericElement)
4964 120993 : return nsGenericElement::CanSkip(tmp, aRemovingAllowed);
4965 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
4966 :
4967 34394 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericElement)
4968 34394 : return nsGenericElement::CanSkipInCC(tmp);
4969 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
4970 :
4971 149113 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGenericElement)
4972 149113 : return nsGenericElement::CanSkipThis(tmp);
4973 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
4974 :
4975 : static const char* kNSURIs[] = {
4976 : " ([none])",
4977 : " (xmlns)",
4978 : " (xml)",
4979 : " (xhtml)",
4980 : " (XLink)",
4981 : " (XSLT)",
4982 : " (XBL)",
4983 : " (MathML)",
4984 : " (RDF)",
4985 : " (XUL)",
4986 : " (SVG)",
4987 : " (XML Events)"
4988 : };
4989 :
4990 45877 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGenericElement)
4991 45877 : if (NS_UNLIKELY(cb.WantDebugInfo())) {
4992 : char name[512];
4993 0 : PRUint32 nsid = tmp->GetNameSpaceID();
4994 0 : nsAtomCString localName(tmp->NodeInfo()->NameAtom());
4995 0 : nsCAutoString uri;
4996 0 : if (tmp->OwnerDoc()->GetDocumentURI()) {
4997 0 : tmp->OwnerDoc()->GetDocumentURI()->GetSpec(uri);
4998 : }
4999 :
5000 0 : nsAutoString id;
5001 0 : nsIAtom* idAtom = tmp->GetID();
5002 0 : if (idAtom) {
5003 0 : id.AppendLiteral(" id='");
5004 0 : id.Append(nsDependentAtomString(idAtom));
5005 0 : id.AppendLiteral("'");
5006 : }
5007 :
5008 0 : nsAutoString classes;
5009 0 : const nsAttrValue* classAttrValue = tmp->GetClasses();
5010 0 : if (classAttrValue) {
5011 0 : classes.AppendLiteral(" class='");
5012 0 : nsAutoString classString;
5013 0 : classAttrValue->ToString(classString);
5014 0 : classes.Append(classString);
5015 0 : classes.AppendLiteral("'");
5016 : }
5017 :
5018 0 : const char* nsuri = nsid < ArrayLength(kNSURIs) ? kNSURIs[nsid] : "";
5019 : PR_snprintf(name, sizeof(name), "nsGenericElement%s %s%s%s %s",
5020 : nsuri,
5021 : localName.get(),
5022 0 : NS_ConvertUTF16toUTF8(id).get(),
5023 0 : NS_ConvertUTF16toUTF8(classes).get(),
5024 0 : uri.get());
5025 : cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsGenericElement),
5026 0 : name);
5027 : }
5028 : else {
5029 45877 : NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGenericElement, tmp->mRefCnt.get())
5030 : }
5031 :
5032 : // Always need to traverse script objects, so do that before we check
5033 : // if we're uncollectable.
5034 45877 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
5035 :
5036 45877 : if (!nsINode::Traverse(tmp, cb)) {
5037 0 : return NS_SUCCESS_INTERRUPTED_TRAVERSE;
5038 : }
5039 :
5040 45877 : tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb);
5041 :
5042 45877 : if (tmp->HasProperties() && tmp->IsXUL()) {
5043 : nsISupports* property =
5044 : static_cast<nsISupports*>
5045 0 : (tmp->GetProperty(nsGkAtoms::contextmenulistener));
5046 0 : cb.NoteXPCOMChild(property);
5047 : property = static_cast<nsISupports*>
5048 0 : (tmp->GetProperty(nsGkAtoms::popuplistener));
5049 0 : cb.NoteXPCOMChild(property);
5050 : }
5051 :
5052 : // Traverse attribute names and child content.
5053 : {
5054 : PRUint32 i;
5055 45877 : PRUint32 attrs = tmp->mAttrsAndChildren.AttrCount();
5056 58439 : for (i = 0; i < attrs; i++) {
5057 12562 : const nsAttrName* name = tmp->mAttrsAndChildren.AttrNameAt(i);
5058 12562 : if (!name->IsAtom()) {
5059 1885 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
5060 : "mAttrsAndChildren[i]->NodeInfo()");
5061 1885 : cb.NoteXPCOMChild(name->NodeInfo());
5062 : }
5063 : }
5064 :
5065 45877 : PRUint32 kids = tmp->mAttrsAndChildren.ChildCount();
5066 179684 : for (i = 0; i < kids; i++) {
5067 133807 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAttrsAndChildren[i]");
5068 133807 : cb.NoteXPCOMChild(tmp->mAttrsAndChildren.GetSafeChildAt(i));
5069 : }
5070 : }
5071 :
5072 : // Traverse any DOM slots of interest.
5073 : {
5074 45877 : nsDOMSlots *slots = tmp->GetExistingDOMSlots();
5075 45877 : if (slots) {
5076 3503 : slots->Traverse(cb, tmp->IsXUL());
5077 : }
5078 : }
5079 45877 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
5080 :
5081 :
5082 1857794 : NS_INTERFACE_MAP_BEGIN(nsGenericElement)
5083 1857794 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
5084 1846872 : NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericElement)
5085 329129 : NS_INTERFACE_MAP_ENTRY(Element)
5086 329129 : NS_INTERFACE_MAP_ENTRY(nsIContent)
5087 56825 : NS_INTERFACE_MAP_ENTRY(nsINode)
5088 45890 : NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
5089 45715 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNSElement, new nsNSElementTearoff(this))
5090 45711 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
5091 : new nsNodeSupportsWeakRefTearoff(this))
5092 45711 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNodeSelector,
5093 : new nsNodeSelectorTearoff(this))
5094 45711 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
5095 : new nsNode3Tearoff(this))
5096 45711 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsITouchEventReceiver,
5097 : new nsTouchEventReceiverTearoff(this))
5098 45711 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIInlineEventHandlers,
5099 : new nsInlineEventHandlersTearoff(this))
5100 : // nsNodeSH::PreCreate() depends on the identity pointer being the
5101 : // same as nsINode (which nsIContent inherits), so if you change the
5102 : // below line, make sure nsNodeSH::PreCreate() still does the right
5103 : // thing!
5104 45711 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
5105 38918 : NS_INTERFACE_MAP_END
5106 :
5107 717438 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGenericElement)
5108 717428 : NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsGenericElement,
5109 : nsNodeUtils::LastRelease(this))
5110 :
5111 : nsresult
5112 993 : nsGenericElement::PostQueryInterface(REFNSIID aIID, void** aInstancePtr)
5113 : {
5114 : return OwnerDoc()->BindingManager()->GetBindingImplementation(this, aIID,
5115 993 : aInstancePtr);
5116 : }
5117 :
5118 : //----------------------------------------------------------------------
5119 : nsresult
5120 0 : nsGenericElement::LeaveLink(nsPresContext* aPresContext)
5121 : {
5122 0 : nsILinkHandler *handler = aPresContext->GetLinkHandler();
5123 0 : if (!handler) {
5124 0 : return NS_OK;
5125 : }
5126 :
5127 0 : return handler->OnLeaveLink();
5128 : }
5129 :
5130 : nsresult
5131 0 : nsGenericElement::AddScriptEventListener(nsIAtom* aEventName,
5132 : const nsAString& aValue,
5133 : bool aDefer)
5134 : {
5135 0 : nsIDocument *ownerDoc = OwnerDoc();
5136 0 : if (ownerDoc->IsLoadedAsData()) {
5137 : // Make this a no-op rather than throwing an error to avoid
5138 : // the error causing problems setting the attribute.
5139 0 : return NS_OK;
5140 : }
5141 :
5142 0 : NS_PRECONDITION(aEventName, "Must have event name!");
5143 0 : bool defer = true;
5144 : nsEventListenerManager* manager = GetEventListenerManagerForAttr(aEventName,
5145 0 : &defer);
5146 0 : if (!manager) {
5147 0 : return NS_OK;
5148 : }
5149 :
5150 0 : defer = defer && aDefer; // only defer if everyone agrees...
5151 0 : PRUint32 lang = GetScriptTypeID();
5152 : manager->AddScriptEventListener(aEventName, aValue, lang, defer,
5153 0 : !nsContentUtils::IsChromeDoc(ownerDoc));
5154 0 : return NS_OK;
5155 : }
5156 :
5157 :
5158 : //----------------------------------------------------------------------
5159 :
5160 : const nsAttrName*
5161 7795 : nsGenericElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
5162 : {
5163 7795 : return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
5164 : }
5165 :
5166 : nsresult
5167 258 : nsGenericElement::CopyInnerTo(nsGenericElement* aDst) const
5168 : {
5169 258 : PRUint32 i, count = mAttrsAndChildren.AttrCount();
5170 425 : for (i = 0; i < count; ++i) {
5171 167 : const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
5172 167 : const nsAttrValue* value = mAttrsAndChildren.AttrAt(i);
5173 334 : nsAutoString valStr;
5174 167 : value->ToString(valStr);
5175 : nsresult rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
5176 167 : name->GetPrefix(), valStr, false);
5177 167 : NS_ENSURE_SUCCESS(rv, rv);
5178 : }
5179 :
5180 258 : return NS_OK;
5181 : }
5182 :
5183 : bool
5184 11455 : nsGenericElement::MaybeCheckSameAttrVal(PRInt32 aNamespaceID,
5185 : nsIAtom* aName,
5186 : nsIAtom* aPrefix,
5187 : const nsAttrValueOrString& aValue,
5188 : bool aNotify,
5189 : nsAttrValue& aOldValue,
5190 : PRUint8* aModType,
5191 : bool* aHasListeners)
5192 : {
5193 11455 : bool modification = false;
5194 : *aHasListeners = aNotify &&
5195 : nsContentUtils::HasMutationListeners(this,
5196 : NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
5197 11455 : this);
5198 :
5199 : // If we have no listeners and aNotify is false, we are almost certainly
5200 : // coming from the content sink and will almost certainly have no previous
5201 : // value. Even if we do, setting the value is cheap when we have no
5202 : // listeners and don't plan to notify. The check for aNotify here is an
5203 : // optimization, the check for *aHasListeners is a correctness issue.
5204 11455 : if (*aHasListeners || aNotify) {
5205 1875 : nsAttrInfo info(GetAttrInfo(aNamespaceID, aName));
5206 1875 : if (info.mValue) {
5207 : // Check whether the old value is the same as the new one. Note that we
5208 : // only need to actually _get_ the old value if we have listeners.
5209 7 : if (*aHasListeners) {
5210 : // Need to store the old value.
5211 : //
5212 : // If the current attribute value contains a pointer to some other data
5213 : // structure that gets updated in the process of setting the attribute
5214 : // we'll no longer have the old value of the attribute. Therefore, we
5215 : // should serialize the attribute value now to keep a snapshot.
5216 : //
5217 : // We have to serialize the value anyway in order to create the
5218 : // mutation event so there's no cost in doing it now.
5219 0 : aOldValue.SetToSerialized(*info.mValue);
5220 : }
5221 7 : bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
5222 7 : if (valueMatches && aPrefix == info.mName->GetPrefix()) {
5223 1 : return true;
5224 : }
5225 6 : modification = true;
5226 : }
5227 : }
5228 : *aModType = modification ?
5229 : static_cast<PRUint8>(nsIDOMMutationEvent::MODIFICATION) :
5230 11454 : static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION);
5231 11454 : return false;
5232 : }
5233 :
5234 : nsresult
5235 11455 : nsGenericElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
5236 : nsIAtom* aPrefix, const nsAString& aValue,
5237 : bool aNotify)
5238 : {
5239 : // Keep this in sync with SetParsedAttr below
5240 :
5241 11455 : NS_ENSURE_ARG_POINTER(aName);
5242 11455 : NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
5243 : "Don't call SetAttr with unknown namespace");
5244 :
5245 11455 : if (!mAttrsAndChildren.CanFitMoreAttrs()) {
5246 0 : return NS_ERROR_FAILURE;
5247 : }
5248 :
5249 : PRUint8 modType;
5250 : bool hasListeners;
5251 22910 : nsAttrValueOrString value(aValue);
5252 22910 : nsAttrValue oldValue;
5253 :
5254 11455 : if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify,
5255 11455 : oldValue, &modType, &hasListeners)) {
5256 1 : return NS_OK;
5257 : }
5258 :
5259 11454 : nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
5260 11454 : NS_ENSURE_SUCCESS(rv, rv);
5261 :
5262 11454 : if (aNotify) {
5263 1874 : nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
5264 : }
5265 :
5266 : // Hold a script blocker while calling ParseAttribute since that can call
5267 : // out to id-observers
5268 22908 : nsAutoScriptBlocker scriptBlocker;
5269 :
5270 22908 : nsAttrValue attrValue;
5271 11454 : if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
5272 11078 : attrValue.SetTo(aValue);
5273 : }
5274 :
5275 : return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
5276 : attrValue, modType, hasListeners, aNotify,
5277 11454 : kCallAfterSetAttr);
5278 : }
5279 :
5280 : nsresult
5281 0 : nsGenericElement::SetParsedAttr(PRInt32 aNamespaceID, nsIAtom* aName,
5282 : nsIAtom* aPrefix, nsAttrValue& aParsedValue,
5283 : bool aNotify)
5284 : {
5285 : // Keep this in sync with SetAttr above
5286 :
5287 0 : NS_ENSURE_ARG_POINTER(aName);
5288 0 : NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
5289 : "Don't call SetAttr with unknown namespace");
5290 :
5291 0 : if (!mAttrsAndChildren.CanFitMoreAttrs()) {
5292 0 : return NS_ERROR_FAILURE;
5293 : }
5294 :
5295 :
5296 : PRUint8 modType;
5297 : bool hasListeners;
5298 0 : nsAttrValueOrString value(aParsedValue);
5299 0 : nsAttrValue oldValue;
5300 :
5301 0 : if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify,
5302 0 : oldValue, &modType, &hasListeners)) {
5303 0 : return NS_OK;
5304 : }
5305 :
5306 0 : nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
5307 0 : NS_ENSURE_SUCCESS(rv, rv);
5308 :
5309 0 : if (aNotify) {
5310 0 : nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
5311 : }
5312 :
5313 : return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
5314 : aParsedValue, modType, hasListeners, aNotify,
5315 0 : kCallAfterSetAttr);
5316 : }
5317 :
5318 : nsresult
5319 11454 : nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
5320 : nsIAtom* aName,
5321 : nsIAtom* aPrefix,
5322 : const nsAttrValue& aOldValue,
5323 : nsAttrValue& aParsedValue,
5324 : PRUint8 aModType,
5325 : bool aFireMutation,
5326 : bool aNotify,
5327 : bool aCallAfterSetAttr)
5328 : {
5329 : nsresult rv;
5330 :
5331 11454 : nsIDocument* document = GetCurrentDoc();
5332 22908 : mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
5333 :
5334 11454 : nsMutationGuard::DidMutate();
5335 :
5336 : // Copy aParsedValue for later use since it will be lost when we call
5337 : // SetAndTakeMappedAttr below
5338 22908 : nsAttrValue aValueForAfterSetAttr;
5339 11454 : if (aCallAfterSetAttr) {
5340 11454 : aValueForAfterSetAttr.SetTo(aParsedValue);
5341 : }
5342 :
5343 11454 : if (aNamespaceID == kNameSpaceID_None) {
5344 : // XXXbz Perhaps we should push up the attribute mapping function
5345 : // stuff to nsGenericElement?
5346 9771 : if (!IsAttributeMapped(aName) ||
5347 0 : !SetMappedAttribute(document, aName, aParsedValue, &rv)) {
5348 9771 : rv = mAttrsAndChildren.SetAndTakeAttr(aName, aParsedValue);
5349 : }
5350 : }
5351 : else {
5352 3366 : nsCOMPtr<nsINodeInfo> ni;
5353 : ni = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix,
5354 : aNamespaceID,
5355 1683 : nsIDOMNode::ATTRIBUTE_NODE);
5356 1683 : NS_ENSURE_TRUE(ni, NS_ERROR_OUT_OF_MEMORY);
5357 :
5358 3366 : rv = mAttrsAndChildren.SetAndTakeAttr(ni, aParsedValue);
5359 : }
5360 11454 : NS_ENSURE_SUCCESS(rv, rv);
5361 :
5362 11454 : if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
5363 : nsRefPtr<nsXBLBinding> binding =
5364 136 : OwnerDoc()->BindingManager()->GetBinding(this);
5365 68 : if (binding) {
5366 0 : binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
5367 : }
5368 : }
5369 :
5370 11454 : UpdateState(aNotify);
5371 :
5372 11454 : if (aNotify) {
5373 1874 : nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
5374 : }
5375 :
5376 11454 : if (aNamespaceID == kNameSpaceID_XMLEvents &&
5377 0 : aName == nsGkAtoms::event && mNodeInfo->GetDocument()) {
5378 0 : mNodeInfo->GetDocument()->AddXMLEventsContent(this);
5379 : }
5380 11454 : if (aCallAfterSetAttr) {
5381 11454 : rv = AfterSetAttr(aNamespaceID, aName, &aValueForAfterSetAttr, aNotify);
5382 11454 : NS_ENSURE_SUCCESS(rv, rv);
5383 : }
5384 :
5385 11454 : if (aFireMutation) {
5386 0 : nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
5387 :
5388 0 : nsCOMPtr<nsIDOMAttr> attrNode;
5389 0 : nsAutoString ns;
5390 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
5391 0 : GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName),
5392 0 : getter_AddRefs(attrNode));
5393 0 : mutation.mRelatedNode = attrNode;
5394 :
5395 0 : mutation.mAttrName = aName;
5396 0 : nsAutoString newValue;
5397 0 : GetAttr(aNamespaceID, aName, newValue);
5398 0 : if (!newValue.IsEmpty()) {
5399 0 : mutation.mNewAttrValue = do_GetAtom(newValue);
5400 : }
5401 0 : if (!aOldValue.IsEmptyString()) {
5402 0 : mutation.mPrevAttrValue = aOldValue.GetAsAtom();
5403 : }
5404 0 : mutation.mAttrChange = aModType;
5405 :
5406 0 : mozAutoSubtreeModified subtree(OwnerDoc(), this);
5407 0 : (new nsAsyncDOMEvent(this, mutation))->RunDOMEventWhenSafe();
5408 : }
5409 :
5410 11454 : return NS_OK;
5411 : }
5412 :
5413 : bool
5414 185 : nsGenericElement::ParseAttribute(PRInt32 aNamespaceID,
5415 : nsIAtom* aAttribute,
5416 : const nsAString& aValue,
5417 : nsAttrValue& aResult)
5418 : {
5419 185 : return false;
5420 : }
5421 :
5422 : bool
5423 0 : nsGenericElement::SetMappedAttribute(nsIDocument* aDocument,
5424 : nsIAtom* aName,
5425 : nsAttrValue& aValue,
5426 : nsresult* aRetval)
5427 : {
5428 0 : *aRetval = NS_OK;
5429 0 : return false;
5430 : }
5431 :
5432 : nsEventListenerManager*
5433 0 : nsGenericElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
5434 : bool* aDefer)
5435 : {
5436 0 : *aDefer = true;
5437 0 : return GetListenerManager(true);
5438 : }
5439 :
5440 : nsGenericElement::nsAttrInfo
5441 3128 : nsGenericElement::GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const
5442 : {
5443 3128 : NS_ASSERTION(nsnull != aName, "must have attribute name");
5444 3128 : NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
5445 : "must have a real namespace ID!");
5446 :
5447 3128 : PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNamespaceID);
5448 3128 : if (index >= 0) {
5449 : return nsAttrInfo(mAttrsAndChildren.AttrNameAt(index),
5450 855 : mAttrsAndChildren.AttrAt(index));
5451 : }
5452 :
5453 2273 : return nsAttrInfo(nsnull, nsnull);
5454 : }
5455 :
5456 :
5457 : bool
5458 9367 : nsGenericElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
5459 : nsAString& aResult) const
5460 : {
5461 9367 : NS_ASSERTION(nsnull != aName, "must have attribute name");
5462 9367 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
5463 : "must have a real namespace ID!");
5464 :
5465 9367 : const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
5466 9367 : if (!val) {
5467 : // Since we are returning a success code we'd better do
5468 : // something about the out parameters (someone may have
5469 : // given us a non-empty string).
5470 283 : aResult.Truncate();
5471 :
5472 283 : return false;
5473 : }
5474 :
5475 9084 : val->ToString(aResult);
5476 :
5477 9084 : return true;
5478 : }
5479 :
5480 : bool
5481 2094 : nsGenericElement::HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const
5482 : {
5483 2094 : NS_ASSERTION(nsnull != aName, "must have attribute name");
5484 2094 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
5485 : "must have a real namespace ID!");
5486 :
5487 2094 : return mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID) >= 0;
5488 : }
5489 :
5490 : bool
5491 692 : nsGenericElement::AttrValueIs(PRInt32 aNameSpaceID,
5492 : nsIAtom* aName,
5493 : const nsAString& aValue,
5494 : nsCaseTreatment aCaseSensitive) const
5495 : {
5496 692 : NS_ASSERTION(aName, "Must have attr name");
5497 692 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
5498 :
5499 692 : const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
5500 692 : return val && val->Equals(aValue, aCaseSensitive);
5501 : }
5502 :
5503 : bool
5504 0 : nsGenericElement::AttrValueIs(PRInt32 aNameSpaceID,
5505 : nsIAtom* aName,
5506 : nsIAtom* aValue,
5507 : nsCaseTreatment aCaseSensitive) const
5508 : {
5509 0 : NS_ASSERTION(aName, "Must have attr name");
5510 0 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
5511 0 : NS_ASSERTION(aValue, "Null value atom");
5512 :
5513 0 : const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
5514 0 : return val && val->Equals(aValue, aCaseSensitive);
5515 : }
5516 :
5517 : PRInt32
5518 3 : nsGenericElement::FindAttrValueIn(PRInt32 aNameSpaceID,
5519 : nsIAtom* aName,
5520 : AttrValuesArray* aValues,
5521 : nsCaseTreatment aCaseSensitive) const
5522 : {
5523 3 : NS_ASSERTION(aName, "Must have attr name");
5524 3 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
5525 3 : NS_ASSERTION(aValues, "Null value array");
5526 :
5527 3 : const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
5528 3 : if (val) {
5529 0 : for (PRInt32 i = 0; aValues[i]; ++i) {
5530 0 : if (val->Equals(*aValues[i], aCaseSensitive)) {
5531 0 : return i;
5532 : }
5533 : }
5534 0 : return ATTR_VALUE_NO_MATCH;
5535 : }
5536 3 : return ATTR_MISSING;
5537 : }
5538 :
5539 : nsresult
5540 0 : nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
5541 : bool aNotify)
5542 : {
5543 0 : NS_ASSERTION(nsnull != aName, "must have attribute name");
5544 :
5545 0 : PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
5546 0 : if (index < 0) {
5547 0 : return NS_OK;
5548 : }
5549 :
5550 0 : nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nsnull, aNotify);
5551 0 : NS_ENSURE_SUCCESS(rv, rv);
5552 :
5553 0 : nsIDocument *document = GetCurrentDoc();
5554 0 : mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
5555 :
5556 0 : if (aNotify) {
5557 : nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
5558 0 : nsIDOMMutationEvent::REMOVAL);
5559 : }
5560 :
5561 : bool hasMutationListeners = aNotify &&
5562 : nsContentUtils::HasMutationListeners(this,
5563 : NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
5564 0 : this);
5565 :
5566 : // Grab the attr node if needed before we remove it from the attr map
5567 0 : nsCOMPtr<nsIDOMAttr> attrNode;
5568 0 : if (hasMutationListeners) {
5569 0 : nsAutoString ns;
5570 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
5571 0 : GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName),
5572 0 : getter_AddRefs(attrNode));
5573 : }
5574 :
5575 : // Clear binding to nsIDOMNamedNodeMap
5576 0 : nsDOMSlots *slots = GetExistingDOMSlots();
5577 0 : if (slots && slots->mAttributeMap) {
5578 0 : slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
5579 : }
5580 :
5581 : // The id-handling code, and in the future possibly other code, need to
5582 : // react to unexpected attribute changes.
5583 0 : nsMutationGuard::DidMutate();
5584 :
5585 0 : nsAttrValue oldValue;
5586 0 : rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
5587 0 : NS_ENSURE_SUCCESS(rv, rv);
5588 :
5589 0 : if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
5590 : nsRefPtr<nsXBLBinding> binding =
5591 0 : OwnerDoc()->BindingManager()->GetBinding(this);
5592 0 : if (binding) {
5593 0 : binding->AttributeChanged(aName, aNameSpaceID, true, aNotify);
5594 : }
5595 : }
5596 :
5597 0 : UpdateState(aNotify);
5598 :
5599 0 : if (aNotify) {
5600 : nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
5601 0 : nsIDOMMutationEvent::REMOVAL);
5602 : }
5603 :
5604 0 : rv = AfterSetAttr(aNameSpaceID, aName, nsnull, aNotify);
5605 0 : NS_ENSURE_SUCCESS(rv, rv);
5606 :
5607 0 : if (hasMutationListeners) {
5608 0 : nsCOMPtr<nsIDOMEventTarget> node = do_QueryObject(this);
5609 0 : nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
5610 :
5611 0 : mutation.mRelatedNode = attrNode;
5612 0 : mutation.mAttrName = aName;
5613 :
5614 0 : nsAutoString value;
5615 0 : oldValue.ToString(value);
5616 0 : if (!value.IsEmpty())
5617 0 : mutation.mPrevAttrValue = do_GetAtom(value);
5618 0 : mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
5619 :
5620 0 : mozAutoSubtreeModified subtree(OwnerDoc(), this);
5621 0 : (new nsAsyncDOMEvent(this, mutation))->RunDOMEventWhenSafe();
5622 : }
5623 :
5624 0 : return NS_OK;
5625 : }
5626 :
5627 : const nsAttrName*
5628 6147 : nsGenericElement::GetAttrNameAt(PRUint32 aIndex) const
5629 : {
5630 6147 : return mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
5631 : }
5632 :
5633 : PRUint32
5634 4270 : nsGenericElement::GetAttrCount() const
5635 : {
5636 4270 : return mAttrsAndChildren.AttrCount();
5637 : }
5638 :
5639 : const nsTextFragment*
5640 0 : nsGenericElement::GetText()
5641 : {
5642 0 : return nsnull;
5643 : }
5644 :
5645 : PRUint32
5646 0 : nsGenericElement::TextLength()
5647 : {
5648 : // We can remove this assertion if it turns out to be useful to be able
5649 : // to depend on this returning 0
5650 0 : NS_NOTREACHED("called nsGenericElement::TextLength");
5651 :
5652 0 : return 0;
5653 : }
5654 :
5655 : nsresult
5656 0 : nsGenericElement::SetText(const PRUnichar* aBuffer, PRUint32 aLength,
5657 : bool aNotify)
5658 : {
5659 0 : NS_ERROR("called nsGenericElement::SetText");
5660 :
5661 0 : return NS_ERROR_FAILURE;
5662 : }
5663 :
5664 : nsresult
5665 0 : nsGenericElement::AppendText(const PRUnichar* aBuffer, PRUint32 aLength,
5666 : bool aNotify)
5667 : {
5668 0 : NS_ERROR("called nsGenericElement::AppendText");
5669 :
5670 0 : return NS_ERROR_FAILURE;
5671 : }
5672 :
5673 : bool
5674 0 : nsGenericElement::TextIsOnlyWhitespace()
5675 : {
5676 0 : return false;
5677 : }
5678 :
5679 : void
5680 0 : nsGenericElement::AppendTextTo(nsAString& aResult)
5681 : {
5682 : // We can remove this assertion if it turns out to be useful to be able
5683 : // to depend on this appending nothing.
5684 0 : NS_NOTREACHED("called nsGenericElement::TextLength");
5685 0 : }
5686 :
5687 : #ifdef DEBUG
5688 : void
5689 0 : nsGenericElement::ListAttributes(FILE* out) const
5690 : {
5691 0 : PRUint32 index, count = mAttrsAndChildren.AttrCount();
5692 0 : for (index = 0; index < count; index++) {
5693 0 : nsAutoString buffer;
5694 :
5695 : // name
5696 0 : mAttrsAndChildren.AttrNameAt(index)->GetQualifiedName(buffer);
5697 :
5698 : // value
5699 0 : buffer.AppendLiteral("=\"");
5700 0 : nsAutoString value;
5701 0 : mAttrsAndChildren.AttrAt(index)->ToString(value);
5702 0 : for (int i = value.Length(); i >= 0; --i) {
5703 0 : if (value[i] == PRUnichar('"'))
5704 0 : value.Insert(PRUnichar('\\'), PRUint32(i));
5705 : }
5706 0 : buffer.Append(value);
5707 0 : buffer.AppendLiteral("\"");
5708 :
5709 0 : fputs(" ", out);
5710 0 : fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
5711 : }
5712 0 : }
5713 :
5714 : void
5715 0 : nsGenericElement::List(FILE* out, PRInt32 aIndent,
5716 : const nsCString& aPrefix) const
5717 : {
5718 : PRInt32 indent;
5719 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
5720 :
5721 0 : fputs(aPrefix.get(), out);
5722 :
5723 0 : fputs(NS_LossyConvertUTF16toASCII(mNodeInfo->QualifiedName()).get(), out);
5724 :
5725 0 : fprintf(out, "@%p", (void *)this);
5726 :
5727 0 : ListAttributes(out);
5728 :
5729 0 : fprintf(out, " state=[%llx]", State().GetInternalValue());
5730 0 : fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
5731 0 : if (IsCommonAncestorForRangeInSelection()) {
5732 : nsRange::RangeHashTable* ranges =
5733 0 : static_cast<nsRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
5734 0 : fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
5735 : }
5736 0 : fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
5737 0 : fprintf(out, " refcount=%d<", mRefCnt.get());
5738 :
5739 0 : nsIContent* child = GetFirstChild();
5740 0 : if (child) {
5741 0 : fputs("\n", out);
5742 :
5743 0 : for (; child; child = child->GetNextSibling()) {
5744 0 : child->List(out, aIndent + 1);
5745 : }
5746 :
5747 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
5748 : }
5749 :
5750 0 : fputs(">\n", out);
5751 :
5752 0 : nsGenericElement* nonConstThis = const_cast<nsGenericElement*>(this);
5753 :
5754 : // XXX sXBL/XBL2 issue! Owner or current document?
5755 0 : nsIDocument *document = OwnerDoc();
5756 :
5757 : // Note: not listing nsIAnonymousContentCreator-created content...
5758 :
5759 0 : nsBindingManager* bindingManager = document->BindingManager();
5760 0 : nsCOMPtr<nsIDOMNodeList> anonymousChildren;
5761 : bindingManager->GetAnonymousNodesFor(nonConstThis,
5762 0 : getter_AddRefs(anonymousChildren));
5763 :
5764 0 : if (anonymousChildren) {
5765 : PRUint32 length;
5766 0 : anonymousChildren->GetLength(&length);
5767 0 : if (length > 0) {
5768 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
5769 0 : fputs("anonymous-children<\n", out);
5770 :
5771 0 : for (PRUint32 i = 0; i < length; ++i) {
5772 0 : nsCOMPtr<nsIDOMNode> node;
5773 0 : anonymousChildren->Item(i, getter_AddRefs(node));
5774 0 : nsCOMPtr<nsIContent> child = do_QueryInterface(node);
5775 0 : child->List(out, aIndent + 1);
5776 : }
5777 :
5778 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
5779 0 : fputs(">\n", out);
5780 : }
5781 : }
5782 :
5783 0 : if (bindingManager->HasContentListFor(nonConstThis)) {
5784 0 : nsCOMPtr<nsIDOMNodeList> contentList;
5785 : bindingManager->GetContentListFor(nonConstThis,
5786 0 : getter_AddRefs(contentList));
5787 :
5788 0 : NS_ASSERTION(contentList != nsnull, "oops, binding manager lied");
5789 :
5790 : PRUint32 length;
5791 0 : contentList->GetLength(&length);
5792 0 : if (length > 0) {
5793 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
5794 0 : fputs("content-list<\n", out);
5795 :
5796 0 : for (PRUint32 i = 0; i < length; ++i) {
5797 0 : nsCOMPtr<nsIDOMNode> node;
5798 0 : contentList->Item(i, getter_AddRefs(node));
5799 0 : nsCOMPtr<nsIContent> child = do_QueryInterface(node);
5800 0 : child->List(out, aIndent + 1);
5801 : }
5802 :
5803 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
5804 0 : fputs(">\n", out);
5805 : }
5806 : }
5807 0 : }
5808 :
5809 : void
5810 0 : nsGenericElement::DumpContent(FILE* out, PRInt32 aIndent,
5811 : bool aDumpAll) const
5812 : {
5813 : PRInt32 indent;
5814 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
5815 :
5816 0 : const nsString& buf = mNodeInfo->QualifiedName();
5817 0 : fputs("<", out);
5818 0 : fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
5819 :
5820 0 : if(aDumpAll) ListAttributes(out);
5821 :
5822 0 : fputs(">", out);
5823 :
5824 0 : if(aIndent) fputs("\n", out);
5825 :
5826 0 : for (nsIContent* child = GetFirstChild();
5827 : child;
5828 0 : child = child->GetNextSibling()) {
5829 0 : PRInt32 indent = aIndent ? aIndent + 1 : 0;
5830 0 : child->DumpContent(out, indent, aDumpAll);
5831 : }
5832 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
5833 0 : fputs("</", out);
5834 0 : fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
5835 0 : fputs(">", out);
5836 :
5837 0 : if(aIndent) fputs("\n", out);
5838 0 : }
5839 : #endif
5840 :
5841 : PRUint32
5842 140781 : nsGenericElement::GetChildCount() const
5843 : {
5844 140781 : return mAttrsAndChildren.ChildCount();
5845 : }
5846 :
5847 : nsIContent *
5848 6629 : nsGenericElement::GetChildAt(PRUint32 aIndex) const
5849 : {
5850 6629 : return mAttrsAndChildren.GetSafeChildAt(aIndex);
5851 : }
5852 :
5853 : nsIContent * const *
5854 287 : nsGenericElement::GetChildArray(PRUint32* aChildCount) const
5855 : {
5856 287 : return mAttrsAndChildren.GetChildArray(aChildCount);
5857 : }
5858 :
5859 : PRInt32
5860 607 : nsGenericElement::IndexOf(nsINode* aPossibleChild) const
5861 : {
5862 607 : return mAttrsAndChildren.IndexOfChild(aPossibleChild);
5863 : }
5864 :
5865 : nsINode::nsSlots*
5866 3306 : nsGenericElement::CreateSlots()
5867 : {
5868 3306 : return new nsDOMSlots();
5869 : }
5870 :
5871 : bool
5872 0 : nsGenericElement::CheckHandleEventForLinksPrecondition(nsEventChainVisitor& aVisitor,
5873 : nsIURI** aURI) const
5874 : {
5875 0 : if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
5876 0 : (!NS_IS_TRUSTED_EVENT(aVisitor.mEvent) &&
5877 : (aVisitor.mEvent->message != NS_MOUSE_CLICK) &&
5878 : (aVisitor.mEvent->message != NS_KEY_PRESS) &&
5879 : (aVisitor.mEvent->message != NS_UI_ACTIVATE)) ||
5880 0 : !aVisitor.mPresContext ||
5881 : (aVisitor.mEvent->flags & NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS)) {
5882 0 : return false;
5883 : }
5884 :
5885 : // Make sure we actually are a link
5886 0 : return IsLink(aURI);
5887 : }
5888 :
5889 : nsresult
5890 0 : nsGenericElement::PreHandleEventForLinks(nsEventChainPreVisitor& aVisitor)
5891 : {
5892 : // Optimisation: return early if this event doesn't interest us.
5893 : // IMPORTANT: this switch and the switch below it must be kept in sync!
5894 0 : switch (aVisitor.mEvent->message) {
5895 : case NS_MOUSE_ENTER_SYNTH:
5896 : case NS_FOCUS_CONTENT:
5897 : case NS_MOUSE_EXIT_SYNTH:
5898 : case NS_BLUR_CONTENT:
5899 : break;
5900 : default:
5901 0 : return NS_OK;
5902 : }
5903 :
5904 : // Make sure we meet the preconditions before continuing
5905 0 : nsCOMPtr<nsIURI> absURI;
5906 0 : if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
5907 0 : return NS_OK;
5908 : }
5909 :
5910 0 : nsresult rv = NS_OK;
5911 :
5912 : // We do the status bar updates in PreHandleEvent so that the status bar gets
5913 : // updated even if the event is consumed before we have a chance to set it.
5914 0 : switch (aVisitor.mEvent->message) {
5915 : // Set the status bar similarly for mouseover and focus
5916 : case NS_MOUSE_ENTER_SYNTH:
5917 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
5918 : // FALL THROUGH
5919 : case NS_FOCUS_CONTENT:
5920 0 : if (aVisitor.mEvent->eventStructType != NS_FOCUS_EVENT ||
5921 0 : !static_cast<nsFocusEvent*>(aVisitor.mEvent)->isRefocus) {
5922 0 : nsAutoString target;
5923 0 : GetLinkTarget(target);
5924 : nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
5925 0 : false, true, true);
5926 : // Make sure any ancestor links don't also TriggerLink
5927 0 : aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
5928 : }
5929 0 : break;
5930 :
5931 : case NS_MOUSE_EXIT_SYNTH:
5932 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
5933 : // FALL THROUGH
5934 : case NS_BLUR_CONTENT:
5935 0 : rv = LeaveLink(aVisitor.mPresContext);
5936 0 : if (NS_SUCCEEDED(rv)) {
5937 0 : aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
5938 : }
5939 0 : break;
5940 :
5941 : default:
5942 : // switch not in sync with the optimization switch earlier in this function
5943 0 : NS_NOTREACHED("switch statements not in sync");
5944 0 : return NS_ERROR_UNEXPECTED;
5945 : }
5946 :
5947 0 : return rv;
5948 : }
5949 :
5950 : nsresult
5951 0 : nsGenericElement::PostHandleEventForLinks(nsEventChainPostVisitor& aVisitor)
5952 : {
5953 : // Optimisation: return early if this event doesn't interest us.
5954 : // IMPORTANT: this switch and the switch below it must be kept in sync!
5955 0 : switch (aVisitor.mEvent->message) {
5956 : case NS_MOUSE_BUTTON_DOWN:
5957 : case NS_MOUSE_CLICK:
5958 : case NS_UI_ACTIVATE:
5959 : case NS_KEY_PRESS:
5960 : break;
5961 : default:
5962 0 : return NS_OK;
5963 : }
5964 :
5965 : // Make sure we meet the preconditions before continuing
5966 0 : nsCOMPtr<nsIURI> absURI;
5967 0 : if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
5968 0 : return NS_OK;
5969 : }
5970 :
5971 0 : nsresult rv = NS_OK;
5972 :
5973 0 : switch (aVisitor.mEvent->message) {
5974 : case NS_MOUSE_BUTTON_DOWN:
5975 : {
5976 0 : if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT &&
5977 : static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
5978 : nsMouseEvent::eLeftButton) {
5979 : // don't make the link grab the focus if there is no link handler
5980 0 : nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler();
5981 0 : nsIDocument *document = GetCurrentDoc();
5982 0 : if (handler && document) {
5983 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
5984 0 : if (fm) {
5985 0 : aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
5986 0 : nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
5987 : fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE |
5988 0 : nsIFocusManager::FLAG_NOSCROLL);
5989 : }
5990 :
5991 : nsEventStateManager::SetActiveManager(
5992 0 : aVisitor.mPresContext->EventStateManager(), this);
5993 : }
5994 : }
5995 : }
5996 0 : break;
5997 :
5998 : case NS_MOUSE_CLICK:
5999 0 : if (NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent)) {
6000 0 : nsInputEvent* inputEvent = static_cast<nsInputEvent*>(aVisitor.mEvent);
6001 0 : if (inputEvent->isControl || inputEvent->isMeta ||
6002 : inputEvent->isAlt ||inputEvent->isShift) {
6003 0 : break;
6004 : }
6005 :
6006 : // The default action is simply to dispatch DOMActivate
6007 0 : nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
6008 0 : if (shell) {
6009 : // single-click
6010 0 : nsEventStatus status = nsEventStatus_eIgnore;
6011 : nsUIEvent actEvent(NS_IS_TRUSTED_EVENT(aVisitor.mEvent),
6012 0 : NS_UI_ACTIVATE, 1);
6013 :
6014 0 : rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
6015 0 : if (NS_SUCCEEDED(rv)) {
6016 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
6017 : }
6018 : }
6019 : }
6020 0 : break;
6021 :
6022 : case NS_UI_ACTIVATE:
6023 : {
6024 0 : if (aVisitor.mEvent->originalTarget == this) {
6025 0 : nsAutoString target;
6026 0 : GetLinkTarget(target);
6027 : nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
6028 0 : true, true, NS_IS_TRUSTED_EVENT(aVisitor.mEvent));
6029 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
6030 : }
6031 : }
6032 0 : break;
6033 :
6034 : case NS_KEY_PRESS:
6035 : {
6036 0 : if (aVisitor.mEvent->eventStructType == NS_KEY_EVENT) {
6037 0 : nsKeyEvent* keyEvent = static_cast<nsKeyEvent*>(aVisitor.mEvent);
6038 0 : if (keyEvent->keyCode == NS_VK_RETURN) {
6039 0 : nsEventStatus status = nsEventStatus_eIgnore;
6040 : rv = DispatchClickEvent(aVisitor.mPresContext, keyEvent, this,
6041 0 : false, 0, &status);
6042 0 : if (NS_SUCCEEDED(rv)) {
6043 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
6044 : }
6045 : }
6046 : }
6047 : }
6048 0 : break;
6049 :
6050 : default:
6051 : // switch not in sync with the optimization switch earlier in this function
6052 0 : NS_NOTREACHED("switch statements not in sync");
6053 0 : return NS_ERROR_UNEXPECTED;
6054 : }
6055 :
6056 0 : return rv;
6057 : }
6058 :
6059 : void
6060 0 : nsGenericElement::FireNodeRemovedForChildren()
6061 : {
6062 0 : nsIDocument* doc = OwnerDoc();
6063 : // Optimize the common case
6064 0 : if (!nsContentUtils::
6065 0 : HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
6066 0 : return;
6067 : }
6068 :
6069 0 : nsCOMPtr<nsIDocument> owningDoc = doc;
6070 :
6071 0 : nsCOMPtr<nsINode> child;
6072 0 : for (child = GetFirstChild();
6073 0 : child && child->GetNodeParent() == this;
6074 0 : child = child->GetNextSibling()) {
6075 0 : nsContentUtils::MaybeFireNodeRemoved(child, this, doc);
6076 : }
6077 : }
6078 :
6079 : void
6080 0 : nsGenericElement::GetLinkTarget(nsAString& aTarget)
6081 : {
6082 0 : aTarget.Truncate();
6083 0 : }
6084 :
6085 : // NOTE: The aPresContext pointer is NOT addrefed.
6086 : // *aSelectorList might be null even if NS_OK is returned; this
6087 : // happens when all the selectors were pseudo-element selectors.
6088 : static nsresult
6089 110 : ParseSelectorList(nsINode* aNode,
6090 : const nsAString& aSelectorString,
6091 : nsCSSSelectorList** aSelectorList)
6092 : {
6093 110 : NS_ENSURE_ARG(aNode);
6094 :
6095 110 : nsIDocument* doc = aNode->OwnerDoc();
6096 220 : nsCSSParser parser(doc->CSSLoader());
6097 :
6098 : nsCSSSelectorList* selectorList;
6099 : nsresult rv = parser.ParseSelectorString(aSelectorString,
6100 : doc->GetDocumentURI(),
6101 : 0, // XXXbz get the line number!
6102 110 : &selectorList);
6103 110 : NS_ENSURE_SUCCESS(rv, rv);
6104 :
6105 : // Filter out pseudo-element selectors from selectorList
6106 110 : nsCSSSelectorList** slot = &selectorList;
6107 110 : do {
6108 110 : nsCSSSelectorList* cur = *slot;
6109 110 : if (cur->mSelectors->IsPseudoElement()) {
6110 0 : *slot = cur->mNext;
6111 0 : cur->mNext = nsnull;
6112 0 : delete cur;
6113 : } else {
6114 110 : slot = &cur->mNext;
6115 : }
6116 : } while (*slot);
6117 110 : *aSelectorList = selectorList;
6118 :
6119 110 : return NS_OK;
6120 : }
6121 :
6122 : // Actually find elements matching aSelectorList (which must not be
6123 : // null) and which are descendants of aRoot and put them in Alist. If
6124 : // onlyFirstMatch, then stop once the first one is found.
6125 : template<bool onlyFirstMatch, class T>
6126 110 : inline static nsresult FindMatchingElements(nsINode* aRoot,
6127 : const nsAString& aSelector,
6128 : T &aList)
6129 : {
6130 220 : nsAutoPtr<nsCSSSelectorList> selectorList;
6131 : nsresult rv = ParseSelectorList(aRoot, aSelector,
6132 110 : getter_Transfers(selectorList));
6133 110 : NS_ENSURE_SUCCESS(rv, rv);
6134 110 : NS_ENSURE_TRUE(selectorList, NS_OK);
6135 :
6136 110 : NS_ASSERTION(selectorList->mSelectors,
6137 : "How can we not have any selectors?");
6138 :
6139 110 : nsIDocument* doc = aRoot->OwnerDoc();
6140 : TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
6141 220 : doc);
6142 110 : doc->FlushPendingLinkUpdates();
6143 :
6144 : // Fast-path selectors involving IDs. We can only do this if aRoot
6145 : // is in the document and the document is not in quirks mode, since
6146 : // ID selectors are case-insensitive in quirks mode. Also, only do
6147 : // this if selectorList only has one selector, because otherwise
6148 : // ordering the elements correctly is a pain.
6149 110 : NS_ASSERTION(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT) ||
6150 : !aRoot->IsInDoc(),
6151 : "The optimization below to check ContentIsDescendantOf only for "
6152 : "elements depends on aRoot being either an element or a "
6153 : "document if it's in the document.");
6154 110 : if (aRoot->IsInDoc() &&
6155 : doc->GetCompatibilityMode() != eCompatibility_NavQuirks &&
6156 : !selectorList->mNext &&
6157 : selectorList->mSelectors->mIDList) {
6158 0 : nsIAtom* id = selectorList->mSelectors->mIDList->mAtom;
6159 : const nsSmallVoidArray* elements =
6160 0 : doc->GetAllElementsForId(nsDependentAtomString(id));
6161 :
6162 : // XXXbz: Should we fall back to the tree walk if aRoot is not the
6163 : // document and |elements| is long, for some value of "long"?
6164 0 : if (elements) {
6165 0 : for (PRInt32 i = 0; i < elements->Count(); ++i) {
6166 0 : Element *element = static_cast<Element*>(elements->ElementAt(i));
6167 0 : if (!aRoot->IsElement() ||
6168 : nsContentUtils::ContentIsDescendantOf(element, aRoot)) {
6169 : // We have an element with the right id and it's a descendant
6170 : // of aRoot. Make sure it really matches the selector.
6171 0 : if (nsCSSRuleProcessor::SelectorListMatches(element, matchingContext,
6172 : selectorList)) {
6173 0 : aList.AppendElement(element);
6174 : if (onlyFirstMatch) {
6175 0 : return NS_OK;
6176 : }
6177 : }
6178 : }
6179 : }
6180 : }
6181 :
6182 : // No elements with this id, or none of them are our descendants,
6183 : // or none of them match. We're done here.
6184 0 : return NS_OK;
6185 : }
6186 :
6187 5244 : for (nsIContent* cur = aRoot->GetFirstChild();
6188 : cur;
6189 : cur = cur->GetNextNode(aRoot)) {
6190 5134 : if (cur->IsElement() &&
6191 : nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
6192 : matchingContext,
6193 : selectorList)) {
6194 164 : aList.AppendElement(cur->AsElement());
6195 : if (onlyFirstMatch) {
6196 0 : return NS_OK;
6197 : }
6198 : }
6199 : }
6200 :
6201 110 : return NS_OK;
6202 : }
6203 :
6204 : struct ElementHolder {
6205 0 : ElementHolder() : mElement(nsnull) {}
6206 0 : void AppendElement(Element* aElement) {
6207 0 : NS_ABORT_IF_FALSE(!mElement, "Should only get one element");
6208 0 : mElement = aElement;
6209 0 : }
6210 : Element* mElement;
6211 : };
6212 :
6213 : /* static */
6214 : nsIContent*
6215 0 : nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
6216 : nsresult *aResult)
6217 : {
6218 0 : NS_PRECONDITION(aResult, "Null out param?");
6219 :
6220 0 : ElementHolder holder;
6221 0 : *aResult = FindMatchingElements<true>(aRoot, aSelector, holder);
6222 :
6223 0 : return holder.mElement;
6224 : }
6225 :
6226 : /* static */
6227 : nsresult
6228 110 : nsGenericElement::doQuerySelectorAll(nsINode* aRoot,
6229 : const nsAString& aSelector,
6230 : nsIDOMNodeList **aReturn)
6231 : {
6232 110 : NS_PRECONDITION(aReturn, "Null out param?");
6233 :
6234 110 : nsSimpleContentList* contentList = new nsSimpleContentList(aRoot);
6235 110 : NS_ENSURE_TRUE(contentList, NS_ERROR_OUT_OF_MEMORY);
6236 110 : NS_ADDREF(*aReturn = contentList);
6237 :
6238 110 : return FindMatchingElements<false>(aRoot, aSelector, *contentList);
6239 : }
6240 :
6241 :
6242 : bool
6243 0 : nsGenericElement::MozMatchesSelector(const nsAString& aSelector, nsresult* aResult)
6244 : {
6245 0 : nsAutoPtr<nsCSSSelectorList> selectorList;
6246 0 : bool matches = false;
6247 :
6248 0 : *aResult = ParseSelectorList(this, aSelector, getter_Transfers(selectorList));
6249 :
6250 0 : if (NS_SUCCEEDED(*aResult)) {
6251 0 : OwnerDoc()->FlushPendingLinkUpdates();
6252 : TreeMatchContext matchingContext(false,
6253 : nsRuleWalker::eRelevantLinkUnvisited,
6254 0 : OwnerDoc());
6255 : matches = nsCSSRuleProcessor::SelectorListMatches(this, matchingContext,
6256 0 : selectorList);
6257 : }
6258 :
6259 0 : return matches;
6260 : }
6261 :
6262 : NS_IMETHODIMP
6263 0 : nsNSElementTearoff::MozMatchesSelector(const nsAString& aSelector, bool* aReturn)
6264 : {
6265 0 : NS_PRECONDITION(aReturn, "Null out param?");
6266 :
6267 : nsresult rv;
6268 0 : *aReturn = mContent->MozMatchesSelector(aSelector, &rv);
6269 :
6270 0 : return rv;
6271 : }
6272 :
6273 : size_t
6274 0 : nsINode::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
6275 : {
6276 0 : size_t n = 0;
6277 : nsEventListenerManager* elm =
6278 0 : const_cast<nsINode*>(this)->GetListenerManager(false);
6279 0 : if (elm) {
6280 0 : n += elm->SizeOfIncludingThis(aMallocSizeOf);
6281 : }
6282 :
6283 : // Measurement of the following members may be added later if DMD finds it is
6284 : // worthwhile:
6285 : // - mNodeInfo (Nb: allocated in nsNodeInfo.cpp with a nsFixedSizeAllocator)
6286 : // - mSlots
6287 : //
6288 : // The following members are not measured:
6289 : // - mParent, mNextSibling, mPreviousSibling, mFirstChild: because they're
6290 : // non-owning
6291 0 : return n;
6292 : }
6293 :
6294 : size_t
6295 0 : nsGenericElement::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
6296 : {
6297 0 : return Element::SizeOfExcludingThis(aMallocSizeOf) +
6298 0 : mAttrsAndChildren.SizeOfExcludingThis(aMallocSizeOf);
6299 : }
6300 :
6301 : static const nsAttrValue::EnumTable kCORSAttributeTable[] = {
6302 : // Order matters here
6303 : // See ParseCORSValue
6304 : { "anonymous", CORS_ANONYMOUS },
6305 : { "use-credentials", CORS_USE_CREDENTIALS },
6306 : { 0 }
6307 : };
6308 :
6309 : /* static */ void
6310 0 : nsGenericElement::ParseCORSValue(const nsAString& aValue,
6311 : nsAttrValue& aResult)
6312 : {
6313 : DebugOnly<bool> success =
6314 : aResult.ParseEnumValue(aValue, kCORSAttributeTable, false,
6315 : // default value is anonymous if aValue is
6316 : // not a value we understand
6317 0 : &kCORSAttributeTable[0]);
6318 0 : MOZ_ASSERT(success);
6319 0 : }
6320 :
6321 : /* static */ CORSMode
6322 0 : nsGenericElement::StringToCORSMode(const nsAString& aValue)
6323 : {
6324 0 : if (aValue.IsVoid()) {
6325 0 : return CORS_NONE;
6326 : }
6327 :
6328 0 : nsAttrValue val;
6329 0 : nsGenericElement::ParseCORSValue(aValue, val);
6330 0 : return CORSMode(val.GetEnumValue());
6331 : }
6332 :
6333 : /* static */ CORSMode
6334 0 : nsGenericElement::AttrValueToCORSMode(const nsAttrValue* aValue)
6335 : {
6336 0 : if (!aValue) {
6337 0 : return CORS_NONE;
6338 : }
6339 :
6340 0 : return CORSMode(aValue->GetEnumValue());
6341 : }
6342 :
6343 : #define EVENT(name_, id_, type_, struct_) \
6344 : NS_IMETHODIMP nsINode::GetOn##name_(JSContext *cx, jsval *vp) { \
6345 : nsEventListenerManager *elm = GetListenerManager(false); \
6346 : if (elm) { \
6347 : elm->GetJSEventListener(nsGkAtoms::on##name_, vp); \
6348 : } else { \
6349 : *vp = JSVAL_NULL; \
6350 : } \
6351 : return NS_OK; \
6352 : } \
6353 : NS_IMETHODIMP nsINode::SetOn##name_(JSContext *cx, const jsval &v) { \
6354 : nsEventListenerManager *elm = GetListenerManager(true); \
6355 : if (!elm) { \
6356 : return NS_ERROR_OUT_OF_MEMORY; \
6357 : } \
6358 : \
6359 : JSObject *obj = GetWrapper(); \
6360 : if (!obj) { \
6361 : /* Just silently do nothing */ \
6362 : return NS_OK; \
6363 : } \
6364 : return elm->SetJSEventListenerToJsval(nsGkAtoms::on##name_, cx, obj, v); \
6365 : }
6366 : #define TOUCH_EVENT EVENT
6367 : #define DOCUMENT_ONLY_EVENT EVENT
6368 : #include "nsEventNameList.h"
6369 : #undef DOCUMENT_ONLY_EVENT
6370 : #undef TOUCH_EVENT
6371 : #undef EVENT
6372 :
6373 : bool
6374 0 : nsINode::Contains(const nsINode* aOther) const
6375 : {
6376 0 : if (aOther == this) {
6377 0 : return true;
6378 : }
6379 0 : if (!aOther ||
6380 0 : OwnerDoc() != aOther->OwnerDoc() ||
6381 0 : IsInDoc() != aOther->IsInDoc() ||
6382 0 : !(aOther->IsElement() ||
6383 0 : aOther->IsNodeOfType(nsINode::eCONTENT)) ||
6384 0 : !GetFirstChild()) {
6385 0 : return false;
6386 : }
6387 :
6388 0 : const nsIContent* other = static_cast<const nsIContent*>(aOther);
6389 0 : if (this == OwnerDoc()) {
6390 : // document.contains(aOther) returns true if aOther is in the document,
6391 : // but is not in any anonymous subtree.
6392 : // IsInDoc() check is done already before this.
6393 0 : return !other->IsInAnonymousSubtree();
6394 : }
6395 :
6396 0 : if (!IsElement() && !IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) {
6397 0 : return false;
6398 : }
6399 :
6400 0 : const nsIContent* thisContent = static_cast<const nsIContent*>(this);
6401 0 : if (thisContent->GetBindingParent() != other->GetBindingParent()) {
6402 0 : return false;
6403 : }
6404 :
6405 0 : return nsContentUtils::ContentIsDescendantOf(other, this);
6406 : }
6407 :
6408 : nsresult
6409 0 : nsINode::Contains(nsIDOMNode* aOther, bool* aReturn)
6410 : {
6411 0 : nsCOMPtr<nsINode> node = do_QueryInterface(aOther);
6412 0 : *aReturn = Contains(node);
6413 0 : return NS_OK;
6414 4392 : }
|