Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /*
8 : * Base class for all element classes; this provides an implementation
9 : * of DOM Core's nsIDOMElement, implements nsIContent, provides
10 : * utility methods for subclasses, and so forth.
11 : */
12 :
13 : #include "mozilla/ArrayUtils.h"
14 : #include "mozilla/Likely.h"
15 : #include "mozilla/MemoryReporting.h"
16 : #include "mozilla/StaticPtr.h"
17 :
18 : #include "mozilla/dom/FragmentOrElement.h"
19 :
20 : #include "mozilla/AsyncEventDispatcher.h"
21 : #include "mozilla/DeclarationBlockInlines.h"
22 : #include "mozilla/EffectSet.h"
23 : #include "mozilla/EventDispatcher.h"
24 : #include "mozilla/EventListenerManager.h"
25 : #include "mozilla/EventStates.h"
26 : #include "mozilla/ServoRestyleManager.h"
27 : #include "mozilla/TextEditor.h"
28 : #include "mozilla/URLExtraData.h"
29 : #include "mozilla/dom/Attr.h"
30 : #include "nsDOMAttributeMap.h"
31 : #include "nsIAtom.h"
32 : #include "mozilla/dom/NodeInfo.h"
33 : #include "mozilla/dom/Event.h"
34 : #include "nsIDocumentInlines.h"
35 : #include "nsIDocumentEncoder.h"
36 : #include "nsIDOMNodeList.h"
37 : #include "nsIContentIterator.h"
38 : #include "nsFocusManager.h"
39 : #include "nsILinkHandler.h"
40 : #include "nsIScriptGlobalObject.h"
41 : #include "nsIURL.h"
42 : #include "nsNetUtil.h"
43 : #include "nsIFrame.h"
44 : #include "nsIAnonymousContentCreator.h"
45 : #include "nsIPresShell.h"
46 : #include "nsPresContext.h"
47 : #include "nsStyleConsts.h"
48 : #include "nsString.h"
49 : #include "nsUnicharUtils.h"
50 : #include "nsIDOMEvent.h"
51 : #include "nsDOMCID.h"
52 : #include "nsIServiceManager.h"
53 : #include "nsIDOMCSSStyleDeclaration.h"
54 : #include "nsDOMCSSAttrDeclaration.h"
55 : #include "nsNameSpaceManager.h"
56 : #include "nsContentList.h"
57 : #include "nsDOMTokenList.h"
58 : #include "nsXBLPrototypeBinding.h"
59 : #include "nsError.h"
60 : #include "nsDOMString.h"
61 : #include "nsIScriptSecurityManager.h"
62 : #include "nsIDOMMutationEvent.h"
63 : #include "mozilla/InternalMutationEvent.h"
64 : #include "mozilla/MouseEvents.h"
65 : #include "nsNodeUtils.h"
66 : #include "nsDocument.h"
67 : #include "nsAttrValueOrString.h"
68 : #ifdef MOZ_XUL
69 : #include "nsXULElement.h"
70 : #endif /* MOZ_XUL */
71 : #include "nsFrameSelection.h"
72 : #ifdef DEBUG
73 : #include "nsRange.h"
74 : #endif
75 :
76 : #include "nsBindingManager.h"
77 : #include "nsXBLBinding.h"
78 : #include "nsPIDOMWindow.h"
79 : #include "nsPIBoxObject.h"
80 : #include "nsSVGUtils.h"
81 : #include "nsLayoutUtils.h"
82 : #include "nsGkAtoms.h"
83 : #include "nsContentUtils.h"
84 : #include "nsTextFragment.h"
85 : #include "nsContentCID.h"
86 :
87 : #include "nsIDOMEventListener.h"
88 : #include "nsIWebNavigation.h"
89 : #include "nsIBaseWindow.h"
90 : #include "nsIWidget.h"
91 :
92 : #include "js/GCAPI.h"
93 :
94 : #include "nsNodeInfoManager.h"
95 : #include "nsICategoryManager.h"
96 : #include "nsGenericHTMLElement.h"
97 : #include "nsContentCreatorFunctions.h"
98 : #include "nsIControllers.h"
99 : #include "nsView.h"
100 : #include "nsViewManager.h"
101 : #include "nsIScrollableFrame.h"
102 : #include "ChildIterator.h"
103 : #include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */
104 : #include "nsRuleProcessorData.h"
105 : #include "nsTextNode.h"
106 : #include "mozilla/dom/NodeListBinding.h"
107 :
108 : #ifdef MOZ_XUL
109 : #include "nsIXULDocument.h"
110 : #endif /* MOZ_XUL */
111 :
112 : #include "nsCCUncollectableMarker.h"
113 :
114 : #include "mozAutoDocUpdate.h"
115 :
116 : #include "mozilla/Sprintf.h"
117 : #include "nsDOMMutationObserver.h"
118 : #include "nsWrapperCacheInlines.h"
119 : #include "nsCycleCollector.h"
120 : #include "xpcpublic.h"
121 : #include "nsIScriptError.h"
122 : #include "mozilla/Telemetry.h"
123 :
124 : #include "mozilla/CORSMode.h"
125 :
126 : #include "mozilla/dom/ShadowRoot.h"
127 : #include "mozilla/dom/HTMLTemplateElement.h"
128 : #include "mozilla/dom/SVGUseElement.h"
129 :
130 : #include "nsStyledElement.h"
131 : #include "nsIContentInlines.h"
132 : #include "nsChildContentList.h"
133 :
134 : using namespace mozilla;
135 : using namespace mozilla::dom;
136 :
137 : int32_t nsIContent::sTabFocusModel = eTabFocus_any;
138 : bool nsIContent::sTabFocusModelAppliesToXUL = false;
139 : uint64_t nsMutationGuard::sGeneration = 0;
140 :
141 : nsIContent*
142 0 : nsIContent::FindFirstNonChromeOnlyAccessContent() const
143 : {
144 : // This handles also nested native anonymous content.
145 0 : for (const nsIContent *content = this; content;
146 0 : content = content->GetBindingParent()) {
147 0 : if (!content->ChromeOnlyAccess()) {
148 : // Oops, this function signature allows casting const to
149 : // non-const. (Then again, so does GetChildAt(0)->GetParent().)
150 0 : return const_cast<nsIContent*>(content);
151 : }
152 : }
153 0 : return nullptr;
154 : }
155 :
156 : nsINode*
157 4363 : nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
158 : {
159 4363 : nsINode* parentNode = GetParentNode();
160 4363 : if (!parentNode || !parentNode->IsContent()) {
161 448 : MOZ_ASSERT(!parentNode || parentNode == OwnerDoc());
162 448 : return parentNode;
163 : }
164 3915 : nsIContent* parent = parentNode->AsContent();
165 :
166 3915 : if (aType == eForStyle &&
167 3915 : IsRootOfNativeAnonymousSubtree() &&
168 0 : OwnerDoc()->GetRootElement() == parent) {
169 : // First, check if this is generated ::before/::after content for the root.
170 : // If it is, we know what to do.
171 0 : if (IsGeneratedContentContainerForBefore() ||
172 0 : IsGeneratedContentContainerForAfter()) {
173 0 : return parent;
174 : }
175 :
176 : // When getting the flattened tree parent for style, we return null
177 : // for any "document level" native anonymous content subtree root.
178 : // This is NAC generated by an ancestor frame of the document element's
179 : // primary frame, and includes scrollbar elements created by the root
180 : // scroll frame, and the "custom content container" and accessible caret
181 : // generated by the nsCanvasFrame. We distinguish document level NAC
182 : // from NAC generated by the root element's primary frame below.
183 0 : nsIFrame* parentFrame = parent->GetPrimaryFrame();
184 0 : if (!parentFrame) {
185 : // If the root element has no primary frame, it means it can't have
186 : // generated any NAC itself. Thus any NAC we have here must have
187 : // been generated by an ancestor frame.
188 : //
189 : // If we are in here, then either the root element is display:none, or
190 : // we are in the middle of constructing the root of the frame tree and
191 : // we are trying to eagerly restyle document level NAC in
192 : // nsCSSFrameConstructor::GetAnonymousContent before the root
193 : // element's frame has been constructed.
194 0 : return nullptr;
195 : }
196 0 : nsIAnonymousContentCreator* creator = do_QueryFrame(parentFrame);
197 0 : if (!creator) {
198 : // If the root element does have a frame, but does not implement
199 : // nsIAnonymousContentCreator, then this must be document level NAC.
200 0 : return nullptr;
201 : }
202 0 : AutoTArray<nsIContent*, 8> elements;
203 0 : creator->AppendAnonymousContentTo(elements, 0);
204 0 : if (!elements.Contains(this)) {
205 : // If the root element does have a frame, and also does implement
206 : // nsIAnonymousContentCreator, but didn't create this node, then
207 : // it must be document level NAC.
208 0 : return nullptr;
209 : }
210 : }
211 :
212 3915 : if (parent && nsContentUtils::HasDistributedChildren(parent) &&
213 0 : nsContentUtils::IsInSameAnonymousTree(parent, this)) {
214 : // This node is distributed to insertion points, thus we
215 : // need to consult the destination insertion points list to
216 : // figure out where this node was inserted in the flattened tree.
217 : // It may be the case that |parent| distributes its children
218 : // but the child does not match any insertion points, thus
219 : // the flattened tree parent is nullptr.
220 0 : nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
221 0 : parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ?
222 0 : destInsertionPoints->LastElement()->GetParent() : nullptr;
223 3915 : } else if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
224 3915 : nsIContent* insertionParent = GetXBLInsertionParent();
225 3915 : if (insertionParent) {
226 989 : parent = insertionParent;
227 : }
228 : }
229 :
230 : // Shadow roots never shows up in the flattened tree. Return the host
231 : // instead.
232 3915 : if (parent && parent->IsInShadowTree()) {
233 0 : ShadowRoot* parentShadowRoot = ShadowRoot::FromNode(parent);
234 0 : if (parentShadowRoot) {
235 0 : return parentShadowRoot->GetHost();
236 : }
237 : }
238 :
239 3915 : return parent;
240 : }
241 :
242 : nsIContent::IMEState
243 0 : nsIContent::GetDesiredIMEState()
244 : {
245 0 : if (!IsEditableInternal()) {
246 : // Check for the special case where we're dealing with elements which don't
247 : // have the editable flag set, but are readwrite (such as text controls).
248 0 : if (!IsElement() ||
249 0 : !AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) {
250 0 : return IMEState(IMEState::DISABLED);
251 : }
252 : }
253 : // NOTE: The content for independent editors (e.g., input[type=text],
254 : // textarea) must override this method, so, we don't need to worry about
255 : // that here.
256 0 : nsIContent *editableAncestor = GetEditingHost();
257 :
258 : // This is in another editable content, use the result of it.
259 0 : if (editableAncestor && editableAncestor != this) {
260 0 : return editableAncestor->GetDesiredIMEState();
261 : }
262 0 : nsIDocument* doc = GetComposedDoc();
263 0 : if (!doc) {
264 0 : return IMEState(IMEState::DISABLED);
265 : }
266 0 : nsIPresShell* ps = doc->GetShell();
267 0 : if (!ps) {
268 0 : return IMEState(IMEState::DISABLED);
269 : }
270 0 : nsPresContext* pc = ps->GetPresContext();
271 0 : if (!pc) {
272 0 : return IMEState(IMEState::DISABLED);
273 : }
274 0 : nsIEditor* editor = nsContentUtils::GetHTMLEditor(pc);
275 0 : if (!editor) {
276 0 : return IMEState(IMEState::DISABLED);
277 : }
278 0 : IMEState state;
279 0 : editor->GetPreferredIMEState(&state);
280 0 : return state;
281 : }
282 :
283 : bool
284 0 : nsIContent::HasIndependentSelection()
285 : {
286 0 : nsIFrame* frame = GetPrimaryFrame();
287 0 : return (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION);
288 : }
289 :
290 : dom::Element*
291 0 : nsIContent::GetEditingHost()
292 : {
293 : // If this isn't editable, return nullptr.
294 0 : if (!IsEditableInternal()) {
295 0 : return nullptr;
296 : }
297 :
298 0 : nsIDocument* doc = GetComposedDoc();
299 0 : if (!doc) {
300 0 : return nullptr;
301 : }
302 :
303 : // If this is in designMode, we should return <body>
304 0 : if (doc->HasFlag(NODE_IS_EDITABLE) && !IsInShadowTree()) {
305 0 : return doc->GetBodyElement();
306 : }
307 :
308 0 : nsIContent* content = this;
309 0 : for (dom::Element* parent = GetParentElement();
310 0 : parent && parent->HasFlag(NODE_IS_EDITABLE);
311 0 : parent = content->GetParentElement()) {
312 0 : content = parent;
313 : }
314 0 : return content->AsElement();
315 : }
316 :
317 : nsresult
318 2 : nsIContent::LookupNamespaceURIInternal(const nsAString& aNamespacePrefix,
319 : nsAString& aNamespaceURI) const
320 : {
321 2 : if (aNamespacePrefix.EqualsLiteral("xml")) {
322 : // Special-case for xml prefix
323 0 : aNamespaceURI.AssignLiteral("http://www.w3.org/XML/1998/namespace");
324 0 : return NS_OK;
325 : }
326 :
327 2 : if (aNamespacePrefix.EqualsLiteral("xmlns")) {
328 : // Special-case for xmlns prefix
329 0 : aNamespaceURI.AssignLiteral("http://www.w3.org/2000/xmlns/");
330 0 : return NS_OK;
331 : }
332 :
333 4 : nsCOMPtr<nsIAtom> name;
334 2 : if (!aNamespacePrefix.IsEmpty()) {
335 2 : name = NS_Atomize(aNamespacePrefix);
336 2 : NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
337 : }
338 : else {
339 0 : name = nsGkAtoms::xmlns;
340 : }
341 : // Trace up the content parent chain looking for the namespace
342 : // declaration that declares aNamespacePrefix.
343 2 : const nsIContent* content = this;
344 3 : do {
345 4 : if (content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI))
346 1 : return NS_OK;
347 3 : } while ((content = content->GetParent()));
348 1 : return NS_ERROR_FAILURE;
349 : }
350 :
351 : nsIAtom*
352 0 : nsIContent::GetLang() const
353 : {
354 0 : for (const auto* content = this; content; content = content->GetParent()) {
355 0 : if (!content->GetAttrCount() || !content->IsElement()) {
356 0 : continue;
357 : }
358 :
359 0 : auto* element = content->AsElement();
360 :
361 : // xml:lang has precedence over lang on HTML elements (see
362 : // XHTML1 section C.7).
363 : const nsAttrValue* attr =
364 0 : element->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
365 0 : if (!attr && element->SupportsLangAttr()) {
366 0 : attr = element->GetParsedAttr(nsGkAtoms::lang);
367 : }
368 0 : if (attr) {
369 0 : MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
370 0 : MOZ_ASSERT(attr->GetAtomValue());
371 0 : return attr->GetAtomValue();
372 : }
373 : }
374 :
375 0 : return nullptr;
376 : }
377 :
378 : already_AddRefed<nsIURI>
379 301 : nsIContent::GetBaseURI(bool aTryUseXHRDocBaseURI) const
380 : {
381 301 : if (IsInAnonymousSubtree() && IsAnonymousContentInSVGUseSubtree()) {
382 46 : nsIContent* bindingParent = GetBindingParent();
383 46 : MOZ_ASSERT(bindingParent);
384 46 : SVGUseElement* useElement = static_cast<SVGUseElement*>(bindingParent);
385 : // XXX Ignore xml:base as we are removing it.
386 46 : return do_AddRef(useElement->GetContentURLData()->BaseURI());
387 : }
388 :
389 255 : nsIDocument* doc = OwnerDoc();
390 : // Start with document base
391 510 : nsCOMPtr<nsIURI> base = doc->GetBaseURI(aTryUseXHRDocBaseURI);
392 :
393 : // Collect array of xml:base attribute values up the parent chain. This
394 : // is slightly slower for the case when there are xml:base attributes, but
395 : // faster for the far more common case of there not being any such
396 : // attributes.
397 : // Also check for SVG elements which require special handling
398 510 : AutoTArray<nsString, 5> baseAttrs;
399 510 : nsString attr;
400 255 : const nsIContent *elem = this;
401 631 : do {
402 : // First check for SVG specialness (why is this SVG specific?)
403 886 : if (elem->IsSVGElement()) {
404 603 : nsIContent* bindingParent = elem->GetBindingParent();
405 603 : if (bindingParent) {
406 0 : nsXBLBinding* binding = bindingParent->GetXBLBinding();
407 0 : if (binding) {
408 : // XXX sXBL/XBL2 issue
409 : // If this is an anonymous XBL element use the binding
410 : // document for the base URI.
411 : // XXX Will fail with xml:base
412 0 : base = binding->PrototypeBinding()->DocURI();
413 0 : break;
414 : }
415 : }
416 : }
417 :
418 : // Otherwise check for xml:base attribute
419 886 : elem->GetAttr(kNameSpaceID_XML, nsGkAtoms::base, attr);
420 886 : if (!attr.IsEmpty()) {
421 0 : baseAttrs.AppendElement(attr);
422 : }
423 886 : elem = elem->GetParent();
424 886 : } while(elem);
425 :
426 255 : if (!baseAttrs.IsEmpty()) {
427 0 : doc->WarnOnceAbout(nsIDocument::eXMLBaseAttribute);
428 : // Now resolve against all xml:base attrs
429 0 : for (uint32_t i = baseAttrs.Length() - 1; i != uint32_t(-1); --i) {
430 0 : nsCOMPtr<nsIURI> newBase;
431 0 : nsresult rv = NS_NewURI(getter_AddRefs(newBase), baseAttrs[i],
432 0 : doc->GetDocumentCharacterSet(), base);
433 : // Do a security check, almost the same as nsDocument::SetBaseURL()
434 : // Only need to do this on the final uri
435 0 : if (NS_SUCCEEDED(rv) && i == 0) {
436 0 : rv = nsContentUtils::GetSecurityManager()->
437 0 : CheckLoadURIWithPrincipal(NodePrincipal(), newBase,
438 0 : nsIScriptSecurityManager::STANDARD);
439 : }
440 0 : if (NS_SUCCEEDED(rv)) {
441 0 : base.swap(newBase);
442 : }
443 : }
444 : }
445 :
446 255 : return base.forget();
447 : }
448 :
449 : nsIURI*
450 8 : nsIContent::GetBaseURIWithoutXMLBase() const
451 : {
452 8 : if (IsInAnonymousSubtree() && IsAnonymousContentInSVGUseSubtree()) {
453 0 : nsIContent* bindingParent = GetBindingParent();
454 0 : MOZ_ASSERT(bindingParent);
455 0 : SVGUseElement* useElement = static_cast<SVGUseElement*>(bindingParent);
456 0 : return useElement->GetContentURLData()->BaseURI();
457 : }
458 : // This also ignores the case that SVG inside XBL binding.
459 : // But it is probably fine.
460 8 : return OwnerDoc()->GetDocBaseURI();
461 : }
462 :
463 : already_AddRefed<nsIURI>
464 8 : nsIContent::GetBaseURIForStyleAttr() const
465 : {
466 8 : nsIDocument* doc = OwnerDoc();
467 8 : nsIURI* baseWithoutXMLBase = GetBaseURIWithoutXMLBase();
468 16 : nsCOMPtr<nsIURI> base = GetBaseURI();
469 : // If eXMLBaseAttribute is not triggered in GetBaseURI() call above,
470 : // we don't need to count eXMLBaseAttributeForStyleAttr either.
471 8 : if (doc->HasWarnedAbout(nsIDocument::eXMLBaseAttribute) &&
472 0 : !doc->HasWarnedAbout(nsIDocument::eXMLBaseAttributeForStyleAttr)) {
473 0 : bool isEqual = false;
474 0 : base->Equals(baseWithoutXMLBase, &isEqual);
475 0 : if (!isEqual) {
476 0 : doc->WarnOnceAbout(nsIDocument::eXMLBaseAttributeForStyleAttr);
477 : }
478 : }
479 8 : return nsLayoutUtils::StyleAttrWithXMLBaseDisabled()
480 16 : ? do_AddRef(baseWithoutXMLBase) : base.forget();
481 : }
482 :
483 : URLExtraData*
484 0 : nsIContent::GetURLDataForStyleAttr() const
485 : {
486 0 : if (IsInAnonymousSubtree() && IsAnonymousContentInSVGUseSubtree()) {
487 0 : nsIContent* bindingParent = GetBindingParent();
488 0 : MOZ_ASSERT(bindingParent);
489 0 : SVGUseElement* useElement = static_cast<SVGUseElement*>(bindingParent);
490 0 : return useElement->GetContentURLData();
491 : }
492 : // We are not going to support xml:base for stylo, but we want to
493 : // ensure we unship that support before we enabling stylo.
494 0 : MOZ_ASSERT(nsLayoutUtils::StyleAttrWithXMLBaseDisabled());
495 : // This also ignores the case that SVG inside XBL binding.
496 : // But it is probably fine.
497 0 : return OwnerDoc()->DefaultStyleAttrURLData();
498 : }
499 :
500 : //----------------------------------------------------------------------
501 :
502 : static inline JSObject*
503 0 : GetJSObjectChild(nsWrapperCache* aCache)
504 : {
505 0 : return aCache->PreservingWrapper() ? aCache->GetWrapperPreserveColor() : nullptr;
506 : }
507 :
508 : static bool
509 0 : NeedsScriptTraverse(nsINode* aNode)
510 : {
511 0 : return aNode->PreservingWrapper() && aNode->GetWrapperPreserveColor() &&
512 0 : !aNode->HasKnownLiveWrapperAndDoesNotNeedTracing(aNode);
513 : }
514 :
515 : //----------------------------------------------------------------------
516 :
517 30 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList)
518 12 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList)
519 :
520 : // If nsChildContentList is changed so that any additional fields are
521 : // traversed by the cycle collector, then CAN_SKIP must be updated to
522 : // check that the additional fields are null.
523 24 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsChildContentList)
524 :
525 : // nsChildContentList only ever has a single child, its wrapper, so if
526 : // the wrapper is known-live, the list can't be part of a garbage cycle.
527 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsChildContentList)
528 0 : return tmp->HasKnownLiveWrapper();
529 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
530 :
531 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsChildContentList)
532 0 : return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(tmp);
533 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
534 :
535 : // CanSkipThis returns false to avoid problems with incomplete unlinking.
536 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsChildContentList)
537 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
538 :
539 88 : NS_INTERFACE_TABLE_HEAD(nsChildContentList)
540 88 : NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
541 80 : NS_INTERFACE_TABLE(nsChildContentList, nsINodeList, nsIDOMNodeList)
542 80 : NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsChildContentList)
543 0 : NS_INTERFACE_MAP_END
544 :
545 : JSObject*
546 8 : nsChildContentList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
547 : {
548 8 : return NodeListBinding::Wrap(cx, this, aGivenProto);
549 : }
550 :
551 : NS_IMETHODIMP
552 38 : nsChildContentList::GetLength(uint32_t* aLength)
553 : {
554 38 : *aLength = mNode ? mNode->GetChildCount() : 0;
555 :
556 38 : return NS_OK;
557 : }
558 :
559 : NS_IMETHODIMP
560 6 : nsChildContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
561 : {
562 6 : nsINode* node = Item(aIndex);
563 6 : if (!node) {
564 0 : *aReturn = nullptr;
565 :
566 0 : return NS_OK;
567 : }
568 :
569 6 : return CallQueryInterface(node, aReturn);
570 : }
571 :
572 : nsIContent*
573 39 : nsChildContentList::Item(uint32_t aIndex)
574 : {
575 39 : if (mNode) {
576 39 : return mNode->GetChildAt(aIndex);
577 : }
578 :
579 0 : return nullptr;
580 : }
581 :
582 : int32_t
583 0 : nsChildContentList::IndexOf(nsIContent* aContent)
584 : {
585 0 : if (mNode) {
586 0 : return mNode->IndexOf(aContent);
587 : }
588 :
589 0 : return -1;
590 : }
591 :
592 : //----------------------------------------------------------------------
593 :
594 : nsIHTMLCollection*
595 5 : FragmentOrElement::Children()
596 : {
597 5 : FragmentOrElement::nsDOMSlots *slots = DOMSlots();
598 :
599 5 : if (!slots->mChildrenList) {
600 : slots->mChildrenList = new nsContentList(this, kNameSpaceID_Wildcard,
601 : nsGkAtoms::_asterisk, nsGkAtoms::_asterisk,
602 5 : false);
603 : }
604 :
605 5 : return slots->mChildrenList;
606 : }
607 :
608 :
609 : //----------------------------------------------------------------------
610 :
611 :
612 581 : NS_IMPL_ISUPPORTS(nsNodeWeakReference,
613 : nsIWeakReference)
614 :
615 26 : nsNodeWeakReference::~nsNodeWeakReference()
616 : {
617 13 : if (mNode) {
618 13 : NS_ASSERTION(mNode->Slots()->mWeakReference == this,
619 : "Weak reference has wrong value");
620 13 : mNode->Slots()->mWeakReference = nullptr;
621 : }
622 13 : }
623 :
624 : NS_IMETHODIMP
625 258 : nsNodeWeakReference::QueryReferent(const nsIID& aIID, void** aInstancePtr)
626 : {
627 258 : return mNode ? mNode->QueryInterface(aIID, aInstancePtr) :
628 258 : NS_ERROR_NULL_POINTER;
629 : }
630 :
631 : size_t
632 0 : nsNodeWeakReference::SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const
633 : {
634 0 : return aMallocSizeOf(this);
635 : }
636 :
637 :
638 0 : NS_IMPL_CYCLE_COLLECTION(nsNodeSupportsWeakRefTearoff, mNode)
639 :
640 675 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeSupportsWeakRefTearoff)
641 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
642 0 : NS_INTERFACE_MAP_END_AGGREGATED(mNode)
643 :
644 135 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeSupportsWeakRefTearoff)
645 405 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeSupportsWeakRefTearoff)
646 :
647 : NS_IMETHODIMP
648 135 : nsNodeSupportsWeakRefTearoff::GetWeakReference(nsIWeakReference** aInstancePtr)
649 : {
650 135 : nsINode::nsSlots* slots = mNode->Slots();
651 135 : if (!slots->mWeakReference) {
652 222 : slots->mWeakReference = new nsNodeWeakReference(mNode);
653 : }
654 :
655 135 : NS_ADDREF(*aInstancePtr = slots->mWeakReference);
656 :
657 135 : return NS_OK;
658 : }
659 :
660 : //----------------------------------------------------------------------
661 981 : FragmentOrElement::nsDOMSlots::nsDOMSlots()
662 : : nsINode::nsSlots(),
663 : mDataset(nullptr),
664 981 : mBindingParent(nullptr)
665 : {
666 981 : }
667 :
668 3 : FragmentOrElement::nsDOMSlots::~nsDOMSlots()
669 : {
670 1 : if (mAttributeMap) {
671 0 : mAttributeMap->DropReference();
672 : }
673 3 : }
674 :
675 : void
676 290 : FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL)
677 : {
678 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle");
679 290 : cb.NoteXPCOMChild(mStyle.get());
680 :
681 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mSMILOverrideStyle");
682 290 : cb.NoteXPCOMChild(mSMILOverrideStyle.get());
683 :
684 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap");
685 290 : cb.NoteXPCOMChild(mAttributeMap.get());
686 :
687 290 : if (aIsXUL) {
688 287 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mControllers");
689 287 : cb.NoteXPCOMChild(mControllers);
690 : }
691 :
692 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLBinding");
693 290 : cb.NoteNativeChild(mXBLBinding, NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
694 :
695 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLInsertionParent");
696 290 : cb.NoteXPCOMChild(mXBLInsertionParent.get());
697 :
698 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mShadowRoot");
699 290 : cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mShadowRoot));
700 :
701 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow");
702 290 : cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
703 :
704 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
705 290 : cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
706 :
707 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mLabelsList");
708 290 : cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mLabelsList));
709 :
710 290 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
711 290 : cb.NoteXPCOMChild(mClassList.get());
712 :
713 290 : if (mCustomElementData) {
714 0 : for (uint32_t i = 0; i < mCustomElementData->mCallbackQueue.Length(); i++) {
715 0 : mCustomElementData->mCallbackQueue[i]->Traverse(cb);
716 : }
717 : }
718 :
719 290 : for (auto iter = mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
720 0 : DOMIntersectionObserver* observer = iter.Key();
721 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mRegisteredIntersectionObservers[i]");
722 0 : cb.NoteXPCOMChild(observer);
723 : }
724 290 : }
725 :
726 : void
727 0 : FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL)
728 : {
729 0 : mStyle = nullptr;
730 0 : mSMILOverrideStyle = nullptr;
731 0 : if (mAttributeMap) {
732 0 : mAttributeMap->DropReference();
733 0 : mAttributeMap = nullptr;
734 : }
735 0 : if (aIsXUL)
736 0 : NS_IF_RELEASE(mControllers);
737 :
738 0 : MOZ_ASSERT(!mXBLBinding);
739 :
740 0 : mXBLInsertionParent = nullptr;
741 0 : mShadowRoot = nullptr;
742 0 : mContainingShadow = nullptr;
743 0 : mChildrenList = nullptr;
744 0 : mLabelsList = nullptr;
745 0 : mCustomElementData = nullptr;
746 0 : mClassList = nullptr;
747 0 : mRegisteredIntersectionObservers.Clear();
748 0 : }
749 :
750 : size_t
751 5 : FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
752 : {
753 5 : size_t n = aMallocSizeOf(this);
754 :
755 5 : if (mAttributeMap) {
756 0 : n += mAttributeMap->SizeOfIncludingThis(aMallocSizeOf);
757 : }
758 :
759 : // Measurement of the following members may be added later if DMD finds it is
760 : // worthwhile:
761 : // - Superclass members (nsINode::nsSlots)
762 : // - mStyle
763 : // - mDataSet
764 : // - mSMILOverrideStyle
765 : // - mSMILOverrideStyleDeclaration
766 : // - mChildrenList
767 : // - mClassList
768 :
769 : // The following members are not measured:
770 : // - mBindingParent / mControllers: because they're non-owning
771 5 : return n;
772 : }
773 :
774 3168 : FragmentOrElement::FragmentOrElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
775 3168 : : nsIContent(aNodeInfo)
776 : {
777 3168 : }
778 :
779 4 : FragmentOrElement::FragmentOrElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
780 4 : : nsIContent(aNodeInfo)
781 : {
782 4 : }
783 :
784 64 : FragmentOrElement::~FragmentOrElement()
785 : {
786 32 : NS_PRECONDITION(!IsInUncomposedDoc(),
787 : "Please remove this from the document properly");
788 32 : if (GetParent()) {
789 0 : NS_RELEASE(mParent);
790 : }
791 32 : }
792 :
793 : already_AddRefed<nsINodeList>
794 0 : FragmentOrElement::GetChildren(uint32_t aFilter)
795 : {
796 0 : RefPtr<nsSimpleContentList> list = new nsSimpleContentList(this);
797 0 : AllChildrenIterator iter(this, aFilter);
798 0 : while (nsIContent* kid = iter.GetNextChild()) {
799 0 : list->AppendElement(kid);
800 0 : }
801 :
802 0 : return list.forget();
803 : }
804 :
805 : static nsIContent*
806 0 : FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
807 : {
808 0 : if (aContent->ChromeOnlyAccess()) {
809 0 : bool chromeAccessOnly = false;
810 0 : while (aContent && !chromeAccessOnly) {
811 0 : chromeAccessOnly = aContent->IsRootOfChromeAccessOnlySubtree();
812 0 : aContent = aContent->GetParent();
813 : }
814 : }
815 0 : return aContent;
816 : }
817 :
818 : nsresult
819 1404 : nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
820 : {
821 : //FIXME! Document how this event retargeting works, Bug 329124.
822 1404 : aVisitor.mCanHandle = true;
823 1404 : aVisitor.mMayHaveListenerManager = HasListenerManager();
824 :
825 : // Don't propagate mouseover and mouseout events when mouse is moving
826 : // inside chrome access only content.
827 1404 : bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
828 4198 : if ((aVisitor.mEvent->mMessage == eMouseOver ||
829 2766 : aVisitor.mEvent->mMessage == eMouseOut ||
830 2738 : aVisitor.mEvent->mMessage == ePointerOver ||
831 2826 : aVisitor.mEvent->mMessage == ePointerOut) &&
832 : // Check if we should stop event propagation when event has just been
833 : // dispatched or when we're about to propagate from
834 : // chrome access only subtree or if we are about to propagate out of
835 : // a shadow root to a shadow root host.
836 60 : ((this == aVisitor.mEvent->mOriginalTarget &&
837 56 : !ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
838 : nsCOMPtr<nsIContent> relatedTarget =
839 8 : do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget);
840 4 : if (relatedTarget &&
841 4 : relatedTarget->OwnerDoc() == OwnerDoc()) {
842 :
843 : // In the web components case, we may need to stop propagation of events
844 : // at shadow root host.
845 0 : if (GetShadowRoot()) {
846 : nsIContent* adjustedTarget =
847 0 : Event::GetShadowRelatedTarget(this, relatedTarget);
848 0 : if (this == adjustedTarget) {
849 0 : aVisitor.mParentTarget = nullptr;
850 0 : aVisitor.mCanHandle = false;
851 0 : return NS_OK;
852 : }
853 : }
854 :
855 : // If current target is anonymous for events or we know that related
856 : // target is descendant of an element which is anonymous for events,
857 : // we may want to stop event propagation.
858 : // If this is the original target, aVisitor.mRelatedTargetIsInAnon
859 : // must be updated.
860 0 : if (isAnonForEvents || aVisitor.mRelatedTargetIsInAnon ||
861 0 : (aVisitor.mEvent->mOriginalTarget == this &&
862 0 : (aVisitor.mRelatedTargetIsInAnon =
863 0 : relatedTarget->ChromeOnlyAccess()))) {
864 0 : nsIContent* anonOwner = FindChromeAccessOnlySubtreeOwner(this);
865 0 : if (anonOwner) {
866 : nsIContent* anonOwnerRelated =
867 0 : FindChromeAccessOnlySubtreeOwner(relatedTarget);
868 0 : if (anonOwnerRelated) {
869 : // Note, anonOwnerRelated may still be inside some other
870 : // native anonymous subtree. The case where anonOwner is still
871 : // inside native anonymous subtree will be handled when event
872 : // propagates up in the DOM tree.
873 0 : while (anonOwner != anonOwnerRelated &&
874 0 : anonOwnerRelated->ChromeOnlyAccess()) {
875 0 : anonOwnerRelated = FindChromeAccessOnlySubtreeOwner(anonOwnerRelated);
876 : }
877 0 : if (anonOwner == anonOwnerRelated) {
878 : #ifdef DEBUG_smaug
879 : nsCOMPtr<nsIContent> originalTarget =
880 : do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
881 : nsAutoString ot, ct, rt;
882 : if (originalTarget) {
883 : originalTarget->NodeInfo()->NameAtom()->ToString(ot);
884 : }
885 : NodeInfo()->NameAtom()->ToString(ct);
886 : relatedTarget->NodeInfo()->NameAtom()->ToString(rt);
887 : printf("Stopping %s propagation:"
888 : "\n\toriginalTarget=%s \n\tcurrentTarget=%s %s"
889 : "\n\trelatedTarget=%s %s \n%s",
890 : (aVisitor.mEvent->mMessage == eMouseOver)
891 : ? "mouseover" : "mouseout",
892 : NS_ConvertUTF16toUTF8(ot).get(),
893 : NS_ConvertUTF16toUTF8(ct).get(),
894 : isAnonForEvents
895 : ? "(is native anonymous)"
896 : : (ChromeOnlyAccess()
897 : ? "(is in native anonymous subtree)" : ""),
898 : NS_ConvertUTF16toUTF8(rt).get(),
899 : relatedTarget->ChromeOnlyAccess()
900 : ? "(is in native anonymous subtree)" : "",
901 : (originalTarget &&
902 : relatedTarget->FindFirstNonChromeOnlyAccessContent() ==
903 : originalTarget->FindFirstNonChromeOnlyAccessContent())
904 : ? "" : "Wrong event propagation!?!\n");
905 : #endif
906 0 : aVisitor.mParentTarget = nullptr;
907 : // Event should not propagate to non-anon content.
908 0 : aVisitor.mCanHandle = isAnonForEvents;
909 0 : return NS_OK;
910 : }
911 : }
912 : }
913 : }
914 : }
915 : }
916 :
917 1404 : nsIContent* parent = GetParent();
918 :
919 : // Web components have a special event chain that need to account
920 : // for destination insertion points where nodes have been distributed.
921 1404 : nsTArray<nsIContent*>* destPoints = GetExistingDestInsertionPoints();
922 1404 : if (destPoints && !destPoints->IsEmpty()) {
923 : // Push destination insertion points to aVisitor.mDestInsertionPoints
924 : // excluding shadow insertion points.
925 0 : bool didPushNonShadowInsertionPoint = false;
926 0 : for (uint32_t i = 0; i < destPoints->Length(); i++) {
927 0 : nsIContent* point = destPoints->ElementAt(i);
928 0 : if (!ShadowRoot::IsShadowInsertionPoint(point)) {
929 0 : aVisitor.mDestInsertionPoints.AppendElement(point);
930 0 : didPushNonShadowInsertionPoint = true;
931 : }
932 : }
933 :
934 : // Next node in the event path is the final destination
935 : // (non-shadow) insertion point that was pushed.
936 0 : if (didPushNonShadowInsertionPoint) {
937 0 : parent = aVisitor.mDestInsertionPoints.LastElement();
938 0 : aVisitor.mDestInsertionPoints.SetLength(
939 0 : aVisitor.mDestInsertionPoints.Length() - 1);
940 : }
941 : }
942 :
943 1404 : ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this);
944 1404 : if (thisShadowRoot) {
945 0 : if (!aVisitor.mEvent->mFlags.mComposed) {
946 : // If we do stop propagation, we still want to propagate
947 : // the event to chrome (nsPIDOMWindow::GetParentTarget()).
948 : // The load event is special in that we don't ever propagate it
949 : // to chrome.
950 0 : nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
951 0 : EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
952 0 : ? win->GetParentTarget() : nullptr;
953 :
954 0 : aVisitor.mParentTarget = parentTarget;
955 0 : return NS_OK;
956 : }
957 :
958 0 : if (!aVisitor.mDestInsertionPoints.IsEmpty()) {
959 0 : parent = aVisitor.mDestInsertionPoints.LastElement();
960 0 : aVisitor.mDestInsertionPoints.SetLength(
961 0 : aVisitor.mDestInsertionPoints.Length() - 1);
962 : } else {
963 : // The pool host for the youngest shadow root is shadow DOM host,
964 : // for older shadow roots, it is the shadow insertion point
965 : // where the shadow root is projected, nullptr if none exists.
966 0 : parent = thisShadowRoot->GetPoolHost();
967 : }
968 : }
969 :
970 : // Event may need to be retargeted if this is the root of a native
971 : // anonymous content subtree or event is dispatched somewhere inside XBL.
972 1404 : if (isAnonForEvents) {
973 : #ifdef DEBUG
974 : // If a DOM event is explicitly dispatched using node.dispatchEvent(), then
975 : // all the events are allowed even in the native anonymous content..
976 : nsCOMPtr<nsIContent> t =
977 2 : do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
978 1 : NS_ASSERTION(!t || !t->ChromeOnlyAccess() ||
979 : aVisitor.mEvent->mClass != eMutationEventClass ||
980 : aVisitor.mDOMEvent,
981 : "Mutation event dispatched in native anonymous content!?!");
982 : #endif
983 1 : aVisitor.mEventTargetAtParent = parent;
984 1403 : } else if (parent && aVisitor.mOriginalTargetIsInAnon) {
985 1470 : nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
986 735 : if (content && content->GetBindingParent() == parent) {
987 90 : aVisitor.mEventTargetAtParent = parent;
988 : }
989 : }
990 :
991 : // check for an anonymous parent
992 : // XXX XBL2/sXBL issue
993 1404 : if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
994 780 : nsIContent* insertionParent = GetXBLInsertionParent();
995 780 : NS_ASSERTION(!(aVisitor.mEventTargetAtParent && insertionParent &&
996 : aVisitor.mEventTargetAtParent != insertionParent),
997 : "Retargeting and having insertion parent!");
998 780 : if (insertionParent) {
999 68 : parent = insertionParent;
1000 : }
1001 : }
1002 :
1003 3476 : if (!aVisitor.mEvent->mFlags.mComposedInNativeAnonymousContent &&
1004 1404 : IsRootOfNativeAnonymousSubtree() && OwnerDoc() &&
1005 0 : OwnerDoc()->GetWindow()) {
1006 0 : aVisitor.mParentTarget = OwnerDoc()->GetWindow()->GetParentTarget();
1007 1404 : } else if (parent) {
1008 1225 : aVisitor.mParentTarget = parent;
1009 : } else {
1010 179 : aVisitor.mParentTarget = GetComposedDoc();
1011 : }
1012 1404 : return NS_OK;
1013 : }
1014 :
1015 : bool
1016 12142 : nsIContent::GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
1017 : nsAString& aResult) const
1018 : {
1019 12142 : if (IsElement()) {
1020 12136 : return AsElement()->GetAttr(aNameSpaceID, aName, aResult);
1021 : }
1022 6 : aResult.Truncate();
1023 6 : return false;
1024 : }
1025 :
1026 : bool
1027 5473 : nsIContent::HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const
1028 : {
1029 5473 : return IsElement() && AsElement()->HasAttr(aNameSpaceID, aName);
1030 : }
1031 :
1032 : bool
1033 231 : nsIContent::AttrValueIs(int32_t aNameSpaceID,
1034 : nsIAtom* aName,
1035 : const nsAString& aValue,
1036 : nsCaseTreatment aCaseSensitive) const
1037 : {
1038 453 : return IsElement() &&
1039 453 : AsElement()->AttrValueIs(aNameSpaceID, aName, aValue, aCaseSensitive);
1040 : }
1041 :
1042 : bool
1043 1188 : nsIContent::AttrValueIs(int32_t aNameSpaceID,
1044 : nsIAtom* aName,
1045 : nsIAtom* aValue,
1046 : nsCaseTreatment aCaseSensitive) const
1047 : {
1048 2376 : return IsElement() &&
1049 2376 : AsElement()->AttrValueIs(aNameSpaceID, aName, aValue, aCaseSensitive);
1050 : }
1051 :
1052 : bool
1053 3 : nsIContent::IsFocusable(int32_t* aTabIndex, bool aWithMouse)
1054 : {
1055 3 : bool focusable = IsFocusableInternal(aTabIndex, aWithMouse);
1056 : // Ensure that the return value and aTabIndex are consistent in the case
1057 : // we're in userfocusignored context.
1058 3 : if (focusable || (aTabIndex && *aTabIndex != -1)) {
1059 3 : if (nsContentUtils::IsUserFocusIgnored(this)) {
1060 0 : if (aTabIndex) {
1061 0 : *aTabIndex = -1;
1062 : }
1063 0 : return false;
1064 : }
1065 3 : return focusable;
1066 : }
1067 0 : return false;
1068 : }
1069 :
1070 : bool
1071 0 : nsIContent::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse)
1072 : {
1073 0 : if (aTabIndex) {
1074 0 : *aTabIndex = -1; // Default, not tabbable
1075 : }
1076 0 : return false;
1077 : }
1078 :
1079 : NS_IMETHODIMP
1080 0 : FragmentOrElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
1081 : {
1082 0 : return NS_OK;
1083 : }
1084 :
1085 : bool
1086 0 : FragmentOrElement::IsLink(nsIURI** aURI) const
1087 : {
1088 0 : *aURI = nullptr;
1089 0 : return false;
1090 : }
1091 :
1092 : nsIContent*
1093 15726 : FragmentOrElement::GetBindingParent() const
1094 : {
1095 15726 : nsDOMSlots *slots = GetExistingDOMSlots();
1096 :
1097 15726 : if (slots) {
1098 3090 : return slots->mBindingParent;
1099 : }
1100 12636 : return nullptr;
1101 : }
1102 :
1103 : nsXBLBinding*
1104 11149 : FragmentOrElement::GetXBLBinding() const
1105 : {
1106 11149 : if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
1107 6580 : nsDOMSlots *slots = GetExistingDOMSlots();
1108 6580 : if (slots) {
1109 6580 : return slots->mXBLBinding;
1110 : }
1111 : }
1112 :
1113 4569 : return nullptr;
1114 : }
1115 :
1116 : void
1117 284 : FragmentOrElement::SetXBLBinding(nsXBLBinding* aBinding,
1118 : nsBindingManager* aOldBindingManager)
1119 : {
1120 : nsBindingManager* bindingManager;
1121 284 : if (aOldBindingManager) {
1122 7 : MOZ_ASSERT(!aBinding, "aOldBindingManager should only be provided "
1123 : "when removing a binding.");
1124 7 : bindingManager = aOldBindingManager;
1125 : } else {
1126 277 : bindingManager = OwnerDoc()->BindingManager();
1127 : }
1128 :
1129 : // After this point, aBinding will be the most-derived binding for aContent.
1130 : // If we already have a binding for aContent, make sure to
1131 : // remove it from the attached stack. Otherwise we might end up firing its
1132 : // constructor twice (if aBinding inherits from it) or firing its constructor
1133 : // after aContent has been deleted (if aBinding is null and the content node
1134 : // dies before we process mAttachedStack).
1135 568 : RefPtr<nsXBLBinding> oldBinding = GetXBLBinding();
1136 284 : if (oldBinding) {
1137 12 : bindingManager->RemoveFromAttachedQueue(oldBinding);
1138 : }
1139 :
1140 284 : if (aBinding) {
1141 272 : SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
1142 272 : nsDOMSlots *slots = DOMSlots();
1143 272 : slots->mXBLBinding = aBinding;
1144 272 : bindingManager->AddBoundContent(this);
1145 : } else {
1146 12 : nsDOMSlots *slots = GetExistingDOMSlots();
1147 12 : if (slots) {
1148 12 : slots->mXBLBinding = nullptr;
1149 : }
1150 12 : bindingManager->RemoveBoundContent(this);
1151 12 : if (oldBinding) {
1152 12 : oldBinding->SetBoundElement(nullptr);
1153 : }
1154 : }
1155 284 : }
1156 :
1157 : nsIContent*
1158 4786 : FragmentOrElement::GetXBLInsertionParent() const
1159 : {
1160 4786 : if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
1161 4693 : nsDOMSlots *slots = GetExistingDOMSlots();
1162 4693 : if (slots) {
1163 4693 : return slots->mXBLInsertionParent;
1164 : }
1165 : }
1166 :
1167 93 : return nullptr;
1168 : }
1169 :
1170 : ShadowRoot*
1171 7177 : FragmentOrElement::GetContainingShadow() const
1172 : {
1173 7177 : nsDOMSlots *slots = GetExistingDOMSlots();
1174 7177 : if (slots) {
1175 553 : return slots->mContainingShadow;
1176 : }
1177 6624 : return nullptr;
1178 : }
1179 :
1180 : void
1181 0 : FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot)
1182 : {
1183 0 : nsDOMSlots *slots = DOMSlots();
1184 0 : slots->mShadowRoot = aShadowRoot;
1185 0 : }
1186 :
1187 : nsTArray<nsIContent*>&
1188 0 : FragmentOrElement::DestInsertionPoints()
1189 : {
1190 0 : nsDOMSlots *slots = DOMSlots();
1191 0 : return slots->mDestInsertionPoints;
1192 : }
1193 :
1194 : nsTArray<nsIContent*>*
1195 1398 : FragmentOrElement::GetExistingDestInsertionPoints() const
1196 : {
1197 1398 : nsDOMSlots *slots = GetExistingDOMSlots();
1198 1398 : if (slots) {
1199 852 : return &slots->mDestInsertionPoints;
1200 : }
1201 546 : return nullptr;
1202 : }
1203 :
1204 : void
1205 496 : FragmentOrElement::SetXBLInsertionParent(nsIContent* aContent)
1206 : {
1207 496 : if (aContent) {
1208 429 : nsDOMSlots *slots = DOMSlots();
1209 429 : SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
1210 429 : slots->mXBLInsertionParent = aContent;
1211 : } else {
1212 67 : nsDOMSlots *slots = GetExistingDOMSlots();
1213 67 : if (slots) {
1214 30 : slots->mXBLInsertionParent = nullptr;
1215 : }
1216 : }
1217 :
1218 : // We just changed the flattened tree, so any Servo style data is now invalid.
1219 : // We rely on nsXBLService::LoadBindings to re-traverse the subtree afterwards.
1220 496 : if (IsStyledByServo() && IsElement() && AsElement()->HasServoData()) {
1221 0 : ServoRestyleManager::ClearServoDataFromSubtree(AsElement());
1222 : }
1223 496 : }
1224 :
1225 : nsresult
1226 3330 : FragmentOrElement::InsertChildAt(nsIContent* aKid,
1227 : uint32_t aIndex,
1228 : bool aNotify)
1229 : {
1230 3330 : NS_PRECONDITION(aKid, "null ptr");
1231 :
1232 3330 : return doInsertChildAt(aKid, aIndex, aNotify, mAttrsAndChildren);
1233 : }
1234 :
1235 : void
1236 109 : FragmentOrElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
1237 : {
1238 218 : nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
1239 109 : NS_ASSERTION(oldKid == GetChildAt(aIndex), "Unexpected child in RemoveChildAt");
1240 :
1241 109 : if (oldKid) {
1242 109 : doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren);
1243 : }
1244 109 : }
1245 :
1246 : void
1247 2 : FragmentOrElement::GetTextContentInternal(nsAString& aTextContent,
1248 : OOMReporter& aError)
1249 : {
1250 2 : if (!nsContentUtils::GetNodeTextContent(this, true, aTextContent, fallible)) {
1251 0 : aError.ReportOOM();
1252 : }
1253 2 : }
1254 :
1255 : void
1256 2 : FragmentOrElement::SetTextContentInternal(const nsAString& aTextContent,
1257 : ErrorResult& aError)
1258 : {
1259 2 : aError = nsContentUtils::SetNodeTextContent(this, aTextContent, false);
1260 2 : }
1261 :
1262 : void
1263 12 : FragmentOrElement::DestroyContent()
1264 : {
1265 : // Drop any servo data. We do this before the RemovedFromDocument call below
1266 : // so that it doesn't need to try to keep the style state sane when shuffling
1267 : // around the flattened tree.
1268 12 : if (IsElement() && AsElement()->HasServoData()) {
1269 0 : AsElement()->ClearServoData();
1270 : }
1271 :
1272 12 : nsIDocument *document = OwnerDoc();
1273 12 : document->BindingManager()->RemovedFromDocument(this, document,
1274 12 : nsBindingManager::eRunDtor);
1275 12 : document->ClearBoxObjectFor(this);
1276 :
1277 12 : uint32_t i, count = mAttrsAndChildren.ChildCount();
1278 20 : for (i = 0; i < count; ++i) {
1279 : // The child can remove itself from the parent in BindToTree.
1280 8 : mAttrsAndChildren.ChildAt(i)->DestroyContent();
1281 : }
1282 12 : ShadowRoot* shadowRoot = GetShadowRoot();
1283 12 : if (shadowRoot) {
1284 0 : shadowRoot->DestroyContent();
1285 : }
1286 12 : }
1287 :
1288 : void
1289 12 : FragmentOrElement::SaveSubtreeState()
1290 : {
1291 12 : uint32_t i, count = mAttrsAndChildren.ChildCount();
1292 20 : for (i = 0; i < count; ++i) {
1293 8 : mAttrsAndChildren.ChildAt(i)->SaveSubtreeState();
1294 : }
1295 12 : }
1296 :
1297 : //----------------------------------------------------------------------
1298 :
1299 : // Generic DOMNode implementations
1300 :
1301 : void
1302 0 : FragmentOrElement::FireNodeInserted(nsIDocument* aDoc,
1303 : nsINode* aParent,
1304 : nsTArray<nsCOMPtr<nsIContent> >& aNodes)
1305 : {
1306 0 : uint32_t count = aNodes.Length();
1307 0 : for (uint32_t i = 0; i < count; ++i) {
1308 0 : nsIContent* childContent = aNodes[i];
1309 :
1310 0 : if (nsContentUtils::HasMutationListeners(childContent,
1311 : NS_EVENT_BITS_MUTATION_NODEINSERTED, aParent)) {
1312 0 : InternalMutationEvent mutation(true, eLegacyNodeInserted);
1313 0 : mutation.mRelatedNode = do_QueryInterface(aParent);
1314 :
1315 0 : mozAutoSubtreeModified subtree(aDoc, aParent);
1316 0 : (new AsyncEventDispatcher(childContent, mutation))->RunDOMEventWhenSafe();
1317 : }
1318 : }
1319 0 : }
1320 :
1321 : //----------------------------------------------------------------------
1322 :
1323 : // nsISupports implementation
1324 :
1325 : #define SUBTREE_UNBINDINGS_PER_RUNNABLE 500
1326 :
1327 : class ContentUnbinder : public Runnable
1328 : {
1329 : public:
1330 0 : ContentUnbinder()
1331 0 : : Runnable("ContentUnbinder")
1332 : {
1333 0 : mLast = this;
1334 0 : }
1335 :
1336 0 : ~ContentUnbinder()
1337 0 : {
1338 0 : Run();
1339 0 : }
1340 :
1341 0 : void UnbindSubtree(nsIContent* aNode)
1342 : {
1343 0 : if (aNode->NodeType() != nsIDOMNode::ELEMENT_NODE &&
1344 0 : aNode->NodeType() != nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
1345 0 : return;
1346 : }
1347 0 : FragmentOrElement* container = static_cast<FragmentOrElement*>(aNode);
1348 0 : uint32_t childCount = container->mAttrsAndChildren.ChildCount();
1349 0 : if (childCount) {
1350 0 : while (childCount-- > 0) {
1351 : // Hold a strong ref to the node when we remove it, because we may be
1352 : // the last reference to it. We need to call TakeChildAt() and
1353 : // update mFirstChild before calling UnbindFromTree, since this last
1354 : // can notify various observers and they should really see consistent
1355 : // tree state.
1356 : // If this code changes, change the corresponding code in
1357 : // FragmentOrElement's and nsDocument's unlink impls.
1358 : nsCOMPtr<nsIContent> child =
1359 0 : container->mAttrsAndChildren.TakeChildAt(childCount);
1360 0 : if (childCount == 0) {
1361 0 : container->mFirstChild = nullptr;
1362 : }
1363 0 : UnbindSubtree(child);
1364 0 : child->UnbindFromTree();
1365 : }
1366 : }
1367 : }
1368 :
1369 0 : NS_IMETHOD Run() override
1370 : {
1371 0 : nsAutoScriptBlocker scriptBlocker;
1372 0 : uint32_t len = mSubtreeRoots.Length();
1373 0 : if (len) {
1374 0 : for (uint32_t i = 0; i < len; ++i) {
1375 0 : UnbindSubtree(mSubtreeRoots[i]);
1376 : }
1377 0 : mSubtreeRoots.Clear();
1378 : }
1379 0 : nsCycleCollector_dispatchDeferredDeletion();
1380 0 : if (this == sContentUnbinder) {
1381 0 : sContentUnbinder = nullptr;
1382 0 : if (mNext) {
1383 0 : RefPtr<ContentUnbinder> next;
1384 0 : next.swap(mNext);
1385 0 : sContentUnbinder = next;
1386 0 : next->mLast = mLast;
1387 0 : mLast = nullptr;
1388 0 : NS_IdleDispatchToCurrentThread(next.forget());
1389 : }
1390 : }
1391 0 : return NS_OK;
1392 : }
1393 :
1394 0 : static void UnbindAll()
1395 : {
1396 0 : RefPtr<ContentUnbinder> ub = sContentUnbinder;
1397 0 : sContentUnbinder = nullptr;
1398 0 : while (ub) {
1399 0 : ub->Run();
1400 0 : ub = ub->mNext;
1401 : }
1402 0 : }
1403 :
1404 0 : static void Append(nsIContent* aSubtreeRoot)
1405 : {
1406 0 : if (!sContentUnbinder) {
1407 0 : sContentUnbinder = new ContentUnbinder();
1408 0 : nsCOMPtr<nsIRunnable> e = sContentUnbinder;
1409 0 : NS_IdleDispatchToCurrentThread(e.forget());
1410 : }
1411 :
1412 0 : if (sContentUnbinder->mLast->mSubtreeRoots.Length() >=
1413 : SUBTREE_UNBINDINGS_PER_RUNNABLE) {
1414 0 : sContentUnbinder->mLast->mNext = new ContentUnbinder();
1415 0 : sContentUnbinder->mLast = sContentUnbinder->mLast->mNext;
1416 : }
1417 0 : sContentUnbinder->mLast->mSubtreeRoots.AppendElement(aSubtreeRoot);
1418 0 : }
1419 :
1420 : private:
1421 : AutoTArray<nsCOMPtr<nsIContent>,
1422 : SUBTREE_UNBINDINGS_PER_RUNNABLE> mSubtreeRoots;
1423 : RefPtr<ContentUnbinder> mNext;
1424 : ContentUnbinder* mLast;
1425 : static ContentUnbinder* sContentUnbinder;
1426 : };
1427 :
1428 : ContentUnbinder* ContentUnbinder::sContentUnbinder = nullptr;
1429 :
1430 : void
1431 0 : FragmentOrElement::ClearContentUnbinder()
1432 : {
1433 0 : ContentUnbinder::UnbindAll();
1434 0 : }
1435 :
1436 : NS_IMPL_CYCLE_COLLECTION_CLASS(FragmentOrElement)
1437 :
1438 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
1439 0 : nsINode::Unlink(tmp);
1440 :
1441 : // The XBL binding is removed by RemoveFromBindingManagerRunnable
1442 : // which is dispatched in UnbindFromTree.
1443 :
1444 0 : if (tmp->HasProperties()) {
1445 0 : if (tmp->IsHTMLElement() || tmp->IsSVGElement()) {
1446 0 : nsIAtom*** props = Element::HTMLSVGPropertiesToTraverseAndUnlink();
1447 0 : for (uint32_t i = 0; props[i]; ++i) {
1448 0 : tmp->DeleteProperty(*props[i]);
1449 : }
1450 0 : if (tmp->MayHaveAnimations()) {
1451 0 : nsIAtom** effectProps = EffectSet::GetEffectSetPropertyAtoms();
1452 0 : for (uint32_t i = 0; effectProps[i]; ++i) {
1453 0 : tmp->DeleteProperty(effectProps[i]);
1454 : }
1455 : }
1456 : }
1457 : }
1458 :
1459 : // Unlink child content (and unbind our subtree).
1460 0 : if (tmp->UnoptimizableCCNode() || !nsCCUncollectableMarker::sGeneration) {
1461 0 : uint32_t childCount = tmp->mAttrsAndChildren.ChildCount();
1462 0 : if (childCount) {
1463 : // Don't allow script to run while we're unbinding everything.
1464 0 : nsAutoScriptBlocker scriptBlocker;
1465 0 : while (childCount-- > 0) {
1466 : // Hold a strong ref to the node when we remove it, because we may be
1467 : // the last reference to it. We need to call TakeChildAt() and
1468 : // update mFirstChild before calling UnbindFromTree, since this last
1469 : // can notify various observers and they should really see consistent
1470 : // tree state.
1471 : // If this code changes, change the corresponding code in nsDocument's
1472 : // unlink impl and ContentUnbinder::UnbindSubtree.
1473 0 : nsCOMPtr<nsIContent> child = tmp->mAttrsAndChildren.TakeChildAt(childCount);
1474 0 : if (childCount == 0) {
1475 0 : tmp->mFirstChild = nullptr;
1476 : }
1477 0 : child->UnbindFromTree();
1478 : }
1479 : }
1480 0 : } else if (!tmp->GetParent() && tmp->mAttrsAndChildren.ChildCount()) {
1481 0 : ContentUnbinder::Append(tmp);
1482 : } /* else {
1483 : The subtree root will end up to a ContentUnbinder, and that will
1484 : unbind the child nodes.
1485 : } */
1486 :
1487 : // Clear flag here because unlinking slots will clear the
1488 : // containing shadow root pointer.
1489 0 : tmp->UnsetFlags(NODE_IS_IN_SHADOW_TREE);
1490 :
1491 0 : nsIDocument* doc = tmp->OwnerDoc();
1492 0 : doc->BindingManager()->RemovedFromDocument(tmp, doc,
1493 0 : nsBindingManager::eDoNotRunDtor);
1494 :
1495 : // Unlink any DOM slots of interest.
1496 : {
1497 0 : nsDOMSlots *slots = tmp->GetExistingDOMSlots();
1498 0 : if (slots) {
1499 0 : if (tmp->IsElement()) {
1500 0 : Element* elem = tmp->AsElement();
1501 0 : for (auto iter = slots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
1502 0 : DOMIntersectionObserver* observer = iter.Key();
1503 0 : observer->UnlinkTarget(*elem);
1504 : }
1505 : }
1506 0 : slots->Unlink(tmp->IsXULElement());
1507 : }
1508 : }
1509 :
1510 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1511 :
1512 1140 : NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(FragmentOrElement)
1513 :
1514 : void
1515 0 : FragmentOrElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
1516 : void* aData)
1517 : {
1518 0 : uint32_t* gen = static_cast<uint32_t*>(aData);
1519 0 : xpc_MarkInCCGeneration(static_cast<nsISupports*>(aChild), *gen);
1520 0 : }
1521 :
1522 : void
1523 0 : FragmentOrElement::MarkNodeChildren(nsINode* aNode)
1524 : {
1525 0 : JSObject* o = GetJSObjectChild(aNode);
1526 0 : if (o) {
1527 0 : JS::ExposeObjectToActiveJS(o);
1528 : }
1529 :
1530 0 : EventListenerManager* elm = aNode->GetExistingListenerManager();
1531 0 : if (elm) {
1532 0 : elm->MarkForCC();
1533 : }
1534 :
1535 0 : if (aNode->HasProperties()) {
1536 0 : nsIDocument* ownerDoc = aNode->OwnerDoc();
1537 : ownerDoc->PropertyTable(DOM_USER_DATA)->
1538 0 : Enumerate(aNode, FragmentOrElement::MarkUserData,
1539 0 : &nsCCUncollectableMarker::sGeneration);
1540 : }
1541 0 : }
1542 :
1543 : nsINode*
1544 0 : FindOptimizableSubtreeRoot(nsINode* aNode)
1545 : {
1546 : nsINode* p;
1547 0 : while ((p = aNode->GetParentNode())) {
1548 0 : if (aNode->UnoptimizableCCNode()) {
1549 0 : return nullptr;
1550 : }
1551 0 : aNode = p;
1552 : }
1553 :
1554 0 : if (aNode->UnoptimizableCCNode()) {
1555 0 : return nullptr;
1556 : }
1557 0 : return aNode;
1558 : }
1559 :
1560 3 : StaticAutoPtr<nsTHashtable<nsPtrHashKey<nsINode>>> gCCBlackMarkedNodes;
1561 :
1562 : static void
1563 0 : ClearBlackMarkedNodes()
1564 : {
1565 0 : if (!gCCBlackMarkedNodes) {
1566 0 : return;
1567 : }
1568 0 : for (auto iter = gCCBlackMarkedNodes->ConstIter(); !iter.Done();
1569 0 : iter.Next()) {
1570 0 : nsINode* n = iter.Get()->GetKey();
1571 0 : n->SetCCMarkedRoot(false);
1572 0 : n->SetInCCBlackTree(false);
1573 : }
1574 0 : gCCBlackMarkedNodes = nullptr;
1575 : }
1576 :
1577 : // static
1578 : void
1579 47 : FragmentOrElement::RemoveBlackMarkedNode(nsINode* aNode)
1580 : {
1581 47 : if (!gCCBlackMarkedNodes) {
1582 47 : return;
1583 : }
1584 0 : gCCBlackMarkedNodes->RemoveEntry(aNode);
1585 : }
1586 :
1587 : static bool
1588 0 : IsCertainlyAliveNode(nsINode* aNode, nsIDocument* aDoc)
1589 : {
1590 0 : MOZ_ASSERT(aNode->GetUncomposedDoc() == aDoc);
1591 :
1592 : // Marked to be in-CC-generation or if the document is an svg image that's
1593 : // being kept alive by the image cache. (Note that an svg image's internal
1594 : // SVG document will receive an OnPageHide() call when it gets purged from
1595 : // the image cache; hence, we use IsVisible() as a hint that the document is
1596 : // actively being kept alive by the cache.)
1597 0 : return nsCCUncollectableMarker::InGeneration(aDoc->GetMarkedCCGeneration()) ||
1598 0 : (nsCCUncollectableMarker::sGeneration &&
1599 0 : aDoc->IsBeingUsedAsImage() &&
1600 0 : aDoc->IsVisible());
1601 : }
1602 :
1603 : // static
1604 : bool
1605 0 : FragmentOrElement::CanSkipInCC(nsINode* aNode)
1606 : {
1607 : // Don't try to optimize anything during shutdown.
1608 0 : if (nsCCUncollectableMarker::sGeneration == 0) {
1609 0 : return false;
1610 : }
1611 :
1612 : //XXXsmaug Need to figure out in which cases Shadow DOM can be optimized out
1613 : // from the CC graph.
1614 0 : nsIDocument* currentDoc = aNode->GetUncomposedDoc();
1615 0 : if (currentDoc && IsCertainlyAliveNode(aNode, currentDoc)) {
1616 0 : return !NeedsScriptTraverse(aNode);
1617 : }
1618 :
1619 : // Bail out early if aNode is somewhere in anonymous content,
1620 : // or otherwise unusual.
1621 0 : if (aNode->UnoptimizableCCNode()) {
1622 0 : return false;
1623 : }
1624 :
1625 : nsINode* root =
1626 0 : currentDoc ? static_cast<nsINode*>(currentDoc) :
1627 0 : FindOptimizableSubtreeRoot(aNode);
1628 0 : if (!root) {
1629 0 : return false;
1630 : }
1631 :
1632 : // Subtree has been traversed already.
1633 0 : if (root->CCMarkedRoot()) {
1634 0 : return root->InCCBlackTree() && !NeedsScriptTraverse(aNode);
1635 : }
1636 :
1637 0 : if (!gCCBlackMarkedNodes) {
1638 0 : gCCBlackMarkedNodes = new nsTHashtable<nsPtrHashKey<nsINode> >(1020);
1639 : }
1640 :
1641 : // nodesToUnpurple contains nodes which will be removed
1642 : // from the purple buffer if the DOM tree is known-live.
1643 0 : AutoTArray<nsIContent*, 1020> nodesToUnpurple;
1644 : // grayNodes need script traverse, so they aren't removed from
1645 : // the purple buffer, but are marked to be in known-live subtree so that
1646 : // traverse is faster.
1647 0 : AutoTArray<nsINode*, 1020> grayNodes;
1648 :
1649 0 : bool foundLiveWrapper = root->HasKnownLiveWrapper();
1650 0 : if (root != currentDoc) {
1651 0 : currentDoc = nullptr;
1652 0 : if (NeedsScriptTraverse(root)) {
1653 0 : grayNodes.AppendElement(root);
1654 0 : } else if (static_cast<nsIContent*>(root)->IsPurple()) {
1655 0 : nodesToUnpurple.AppendElement(static_cast<nsIContent*>(root));
1656 : }
1657 : }
1658 :
1659 : // Traverse the subtree and check if we could know without CC
1660 : // that it is known-live.
1661 : // Note, this traverse is non-virtual and inline, so it should be a lot faster
1662 : // than CC's generic traverse.
1663 0 : for (nsIContent* node = root->GetFirstChild(); node;
1664 0 : node = node->GetNextNode(root)) {
1665 0 : foundLiveWrapper = foundLiveWrapper || node->HasKnownLiveWrapper();
1666 0 : if (foundLiveWrapper && currentDoc) {
1667 : // If we can mark the whole document known-live, no need to optimize
1668 : // so much, since when the next purple node in the document will be
1669 : // handled, it is fast to check that currentDoc is in CCGeneration.
1670 0 : break;
1671 : }
1672 0 : if (NeedsScriptTraverse(node)) {
1673 : // Gray nodes need real CC traverse.
1674 0 : grayNodes.AppendElement(node);
1675 0 : } else if (node->IsPurple()) {
1676 0 : nodesToUnpurple.AppendElement(node);
1677 : }
1678 : }
1679 :
1680 0 : root->SetCCMarkedRoot(true);
1681 0 : root->SetInCCBlackTree(foundLiveWrapper);
1682 0 : gCCBlackMarkedNodes->PutEntry(root);
1683 :
1684 0 : if (!foundLiveWrapper) {
1685 0 : return false;
1686 : }
1687 :
1688 0 : if (currentDoc) {
1689 : // Special case documents. If we know the document is known-live,
1690 : // we can mark the document to be in CCGeneration.
1691 : currentDoc->
1692 0 : MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
1693 : } else {
1694 0 : for (uint32_t i = 0; i < grayNodes.Length(); ++i) {
1695 0 : nsINode* node = grayNodes[i];
1696 0 : node->SetInCCBlackTree(true);
1697 0 : gCCBlackMarkedNodes->PutEntry(node);
1698 : }
1699 : }
1700 :
1701 : // Subtree is known-live, we can remove non-gray purple nodes from
1702 : // purple buffer.
1703 0 : for (uint32_t i = 0; i < nodesToUnpurple.Length(); ++i) {
1704 0 : nsIContent* purple = nodesToUnpurple[i];
1705 : // Can't remove currently handled purple node.
1706 0 : if (purple != aNode) {
1707 0 : purple->RemovePurple();
1708 : }
1709 : }
1710 0 : return !NeedsScriptTraverse(aNode);
1711 : }
1712 :
1713 : AutoTArray<nsINode*, 1020>* gPurpleRoots = nullptr;
1714 : AutoTArray<nsIContent*, 1020>* gNodesToUnbind = nullptr;
1715 :
1716 0 : void ClearCycleCollectorCleanupData()
1717 : {
1718 0 : if (gPurpleRoots) {
1719 0 : uint32_t len = gPurpleRoots->Length();
1720 0 : for (uint32_t i = 0; i < len; ++i) {
1721 0 : nsINode* n = gPurpleRoots->ElementAt(i);
1722 0 : n->SetIsPurpleRoot(false);
1723 : }
1724 0 : delete gPurpleRoots;
1725 0 : gPurpleRoots = nullptr;
1726 : }
1727 0 : if (gNodesToUnbind) {
1728 0 : uint32_t len = gNodesToUnbind->Length();
1729 0 : for (uint32_t i = 0; i < len; ++i) {
1730 0 : nsIContent* c = gNodesToUnbind->ElementAt(i);
1731 0 : c->SetIsPurpleRoot(false);
1732 0 : ContentUnbinder::Append(c);
1733 : }
1734 0 : delete gNodesToUnbind;
1735 0 : gNodesToUnbind = nullptr;
1736 : }
1737 0 : }
1738 :
1739 : static bool
1740 0 : ShouldClearPurple(nsIContent* aContent)
1741 : {
1742 0 : MOZ_ASSERT(aContent);
1743 0 : if (aContent->IsPurple()) {
1744 0 : return true;
1745 : }
1746 :
1747 0 : JSObject* o = GetJSObjectChild(aContent);
1748 0 : if (o && JS::ObjectIsMarkedGray(o)) {
1749 0 : return true;
1750 : }
1751 :
1752 0 : if (aContent->HasListenerManager()) {
1753 0 : return true;
1754 : }
1755 :
1756 0 : return aContent->HasProperties();
1757 : }
1758 :
1759 : // If aNode is not optimizable, but is an element
1760 : // with a frame in a document which has currently active presshell,
1761 : // we can act as if it was optimizable. When the primary frame dies, aNode
1762 : // will end up to the purple buffer because of the refcount change.
1763 : bool
1764 0 : NodeHasActiveFrame(nsIDocument* aCurrentDoc, nsINode* aNode)
1765 : {
1766 0 : return aCurrentDoc->GetShell() && aNode->IsElement() &&
1767 0 : aNode->AsElement()->GetPrimaryFrame();
1768 : }
1769 :
1770 : bool
1771 0 : OwnedByBindingManager(nsIDocument* aCurrentDoc, nsINode* aNode)
1772 : {
1773 0 : return aNode->IsElement() && aNode->AsElement()->GetXBLBinding();
1774 : }
1775 :
1776 : // CanSkip checks if aNode is known-live, and if it is, returns true. If aNode
1777 : // is in a known-live DOM tree, CanSkip may also remove other objects from
1778 : // purple buffer and unmark event listeners and user data. If the root of the
1779 : // DOM tree is a document, less optimizations are done since checking the
1780 : // liveness of the current document is usually fast and we don't want slow down
1781 : // such common cases.
1782 : bool
1783 0 : FragmentOrElement::CanSkip(nsINode* aNode, bool aRemovingAllowed)
1784 : {
1785 : // Don't try to optimize anything during shutdown.
1786 0 : if (nsCCUncollectableMarker::sGeneration == 0) {
1787 0 : return false;
1788 : }
1789 :
1790 0 : bool unoptimizable = aNode->UnoptimizableCCNode();
1791 0 : nsIDocument* currentDoc = aNode->GetUncomposedDoc();
1792 0 : if (currentDoc && IsCertainlyAliveNode(aNode, currentDoc) &&
1793 0 : (!unoptimizable || NodeHasActiveFrame(currentDoc, aNode) ||
1794 0 : OwnedByBindingManager(currentDoc, aNode))) {
1795 0 : MarkNodeChildren(aNode);
1796 0 : return true;
1797 : }
1798 :
1799 0 : if (unoptimizable) {
1800 0 : return false;
1801 : }
1802 :
1803 0 : nsINode* root = currentDoc ? static_cast<nsINode*>(currentDoc) :
1804 0 : FindOptimizableSubtreeRoot(aNode);
1805 0 : if (!root) {
1806 0 : return false;
1807 : }
1808 :
1809 : // Subtree has been traversed already, and aNode has
1810 : // been handled in a way that doesn't require revisiting it.
1811 0 : if (root->IsPurpleRoot()) {
1812 0 : return false;
1813 : }
1814 :
1815 : // nodesToClear contains nodes which are either purple or
1816 : // gray.
1817 0 : AutoTArray<nsIContent*, 1020> nodesToClear;
1818 :
1819 0 : bool foundLiveWrapper = root->HasKnownLiveWrapper();
1820 0 : bool domOnlyCycle = false;
1821 0 : if (root != currentDoc) {
1822 0 : currentDoc = nullptr;
1823 0 : if (!foundLiveWrapper) {
1824 0 : domOnlyCycle = static_cast<nsIContent*>(root)->OwnedOnlyByTheDOMTree();
1825 : }
1826 0 : if (ShouldClearPurple(static_cast<nsIContent*>(root))) {
1827 0 : nodesToClear.AppendElement(static_cast<nsIContent*>(root));
1828 : }
1829 : }
1830 :
1831 : // Traverse the subtree and check if we could know without CC
1832 : // that it is known-live.
1833 : // Note, this traverse is non-virtual and inline, so it should be a lot faster
1834 : // than CC's generic traverse.
1835 0 : for (nsIContent* node = root->GetFirstChild(); node;
1836 0 : node = node->GetNextNode(root)) {
1837 0 : foundLiveWrapper = foundLiveWrapper || node->HasKnownLiveWrapper();
1838 0 : if (foundLiveWrapper) {
1839 0 : domOnlyCycle = false;
1840 0 : if (currentDoc) {
1841 : // If we can mark the whole document live, no need to optimize
1842 : // so much, since when the next purple node in the document will be
1843 : // handled, it is fast to check that the currentDoc is in CCGeneration.
1844 0 : break;
1845 : }
1846 : // No need to put stuff to the nodesToClear array, if we can clear it
1847 : // already here.
1848 0 : if (node->IsPurple() && (node != aNode || aRemovingAllowed)) {
1849 0 : node->RemovePurple();
1850 : }
1851 0 : MarkNodeChildren(node);
1852 : } else {
1853 0 : domOnlyCycle = domOnlyCycle && node->OwnedOnlyByTheDOMTree();
1854 0 : if (ShouldClearPurple(node)) {
1855 : // Collect interesting nodes which we can clear if we find that
1856 : // they are kept alive in a known-live tree or are in a DOM-only cycle.
1857 0 : nodesToClear.AppendElement(node);
1858 : }
1859 : }
1860 : }
1861 :
1862 0 : if (!currentDoc || !foundLiveWrapper) {
1863 0 : root->SetIsPurpleRoot(true);
1864 0 : if (domOnlyCycle) {
1865 0 : if (!gNodesToUnbind) {
1866 0 : gNodesToUnbind = new AutoTArray<nsIContent*, 1020>();
1867 : }
1868 0 : gNodesToUnbind->AppendElement(static_cast<nsIContent*>(root));
1869 0 : for (uint32_t i = 0; i < nodesToClear.Length(); ++i) {
1870 0 : nsIContent* n = nodesToClear[i];
1871 0 : if ((n != aNode || aRemovingAllowed) && n->IsPurple()) {
1872 0 : n->RemovePurple();
1873 : }
1874 : }
1875 0 : return true;
1876 : } else {
1877 0 : if (!gPurpleRoots) {
1878 0 : gPurpleRoots = new AutoTArray<nsINode*, 1020>();
1879 : }
1880 0 : gPurpleRoots->AppendElement(root);
1881 : }
1882 : }
1883 :
1884 0 : if (!foundLiveWrapper) {
1885 0 : return false;
1886 : }
1887 :
1888 0 : if (currentDoc) {
1889 : // Special case documents. If we know the document is known-live,
1890 : // we can mark the document to be in CCGeneration.
1891 : currentDoc->
1892 0 : MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
1893 0 : MarkNodeChildren(currentDoc);
1894 : }
1895 :
1896 : // Subtree is known-live, so we can remove purple nodes from
1897 : // purple buffer and mark stuff that to be certainly alive.
1898 0 : for (uint32_t i = 0; i < nodesToClear.Length(); ++i) {
1899 0 : nsIContent* n = nodesToClear[i];
1900 0 : MarkNodeChildren(n);
1901 : // Can't remove currently handled purple node,
1902 : // unless aRemovingAllowed is true.
1903 0 : if ((n != aNode || aRemovingAllowed) && n->IsPurple()) {
1904 0 : n->RemovePurple();
1905 : }
1906 : }
1907 0 : return true;
1908 : }
1909 :
1910 : bool
1911 0 : FragmentOrElement::CanSkipThis(nsINode* aNode)
1912 : {
1913 0 : if (nsCCUncollectableMarker::sGeneration == 0) {
1914 0 : return false;
1915 : }
1916 0 : if (aNode->HasKnownLiveWrapper()) {
1917 0 : return true;
1918 : }
1919 0 : nsIDocument* c = aNode->GetUncomposedDoc();
1920 : return
1921 0 : ((c && IsCertainlyAliveNode(aNode, c)) || aNode->InCCBlackTree()) &&
1922 0 : !NeedsScriptTraverse(aNode);
1923 : }
1924 :
1925 : void
1926 3 : FragmentOrElement::InitCCCallbacks()
1927 : {
1928 3 : nsCycleCollector_setForgetSkippableCallback(ClearCycleCollectorCleanupData);
1929 3 : nsCycleCollector_setBeforeUnlinkCallback(ClearBlackMarkedNodes);
1930 3 : }
1931 :
1932 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(FragmentOrElement)
1933 0 : return FragmentOrElement::CanSkip(tmp, aRemovingAllowed);
1934 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1935 :
1936 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(FragmentOrElement)
1937 0 : return FragmentOrElement::CanSkipInCC(tmp);
1938 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1939 :
1940 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(FragmentOrElement)
1941 0 : return FragmentOrElement::CanSkipThis(tmp);
1942 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1943 :
1944 : static const char* kNSURIs[] = {
1945 : " ([none])",
1946 : " (xmlns)",
1947 : " (xml)",
1948 : " (xhtml)",
1949 : " (XLink)",
1950 : " (XSLT)",
1951 : " (XBL)",
1952 : " (MathML)",
1953 : " (RDF)",
1954 : " (XUL)",
1955 : " (SVG)",
1956 : " (XML Events)"
1957 : };
1958 :
1959 432 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
1960 432 : if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
1961 : char name[512];
1962 0 : uint32_t nsid = tmp->GetNameSpaceID();
1963 0 : nsAtomCString localName(tmp->NodeInfo()->NameAtom());
1964 0 : nsAutoCString uri;
1965 0 : if (tmp->OwnerDoc()->GetDocumentURI()) {
1966 0 : uri = tmp->OwnerDoc()->GetDocumentURI()->GetSpecOrDefault();
1967 : }
1968 :
1969 0 : nsAutoString id;
1970 0 : nsIAtom* idAtom = tmp->GetID();
1971 0 : if (idAtom) {
1972 0 : id.AppendLiteral(" id='");
1973 0 : id.Append(nsDependentAtomString(idAtom));
1974 0 : id.Append('\'');
1975 : }
1976 :
1977 0 : nsAutoString classes;
1978 0 : const nsAttrValue* classAttrValue = tmp->IsElement() ?
1979 0 : tmp->AsElement()->GetClasses() : nullptr;
1980 0 : if (classAttrValue) {
1981 0 : classes.AppendLiteral(" class='");
1982 0 : nsAutoString classString;
1983 0 : classAttrValue->ToString(classString);
1984 0 : classString.ReplaceChar(char16_t('\n'), char16_t(' '));
1985 0 : classes.Append(classString);
1986 0 : classes.Append('\'');
1987 : }
1988 :
1989 0 : nsAutoCString orphan;
1990 0 : if (!tmp->IsInUncomposedDoc() &&
1991 : // Ignore xbl:content, which is never in the document and hence always
1992 : // appears to be orphaned.
1993 0 : !tmp->NodeInfo()->Equals(nsGkAtoms::content, kNameSpaceID_XBL)) {
1994 0 : orphan.AppendLiteral(" (orphan)");
1995 : }
1996 :
1997 0 : const char* nsuri = nsid < ArrayLength(kNSURIs) ? kNSURIs[nsid] : "";
1998 0 : SprintfLiteral(name, "FragmentOrElement%s %s%s%s%s %s",
1999 : nsuri,
2000 : localName.get(),
2001 0 : NS_ConvertUTF16toUTF8(id).get(),
2002 0 : NS_ConvertUTF16toUTF8(classes).get(),
2003 : orphan.get(),
2004 0 : uri.get());
2005 0 : cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
2006 : }
2007 : else {
2008 432 : NS_IMPL_CYCLE_COLLECTION_DESCRIBE(FragmentOrElement, tmp->mRefCnt.get())
2009 : }
2010 :
2011 432 : if (!nsINode::Traverse(tmp, cb)) {
2012 0 : return NS_SUCCESS_INTERRUPTED_TRAVERSE;
2013 : }
2014 :
2015 432 : tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb);
2016 :
2017 : // Check that whenever we have effect properties, MayHaveAnimations is set.
2018 : #ifdef DEBUG
2019 432 : nsIAtom** effectProps = EffectSet::GetEffectSetPropertyAtoms();
2020 1728 : for (uint32_t i = 0; effectProps[i]; ++i) {
2021 1296 : MOZ_ASSERT_IF(tmp->GetProperty(effectProps[i]), tmp->MayHaveAnimations());
2022 : }
2023 : #endif
2024 :
2025 432 : if (tmp->HasProperties()) {
2026 1 : if (tmp->IsHTMLElement() || tmp->IsSVGElement()) {
2027 0 : nsIAtom*** props = Element::HTMLSVGPropertiesToTraverseAndUnlink();
2028 0 : for (uint32_t i = 0; props[i]; ++i) {
2029 : nsISupports* property =
2030 0 : static_cast<nsISupports*>(tmp->GetProperty(*props[i]));
2031 0 : cb.NoteXPCOMChild(property);
2032 : }
2033 0 : if (tmp->MayHaveAnimations()) {
2034 0 : nsIAtom** effectProps = EffectSet::GetEffectSetPropertyAtoms();
2035 0 : for (uint32_t i = 0; effectProps[i]; ++i) {
2036 : EffectSet* effectSet =
2037 0 : static_cast<EffectSet*>(tmp->GetProperty(effectProps[i]));
2038 0 : if (effectSet) {
2039 0 : effectSet->Traverse(cb);
2040 : }
2041 : }
2042 : }
2043 : }
2044 : }
2045 :
2046 : // Traverse attribute names and child content.
2047 : {
2048 : uint32_t i;
2049 432 : uint32_t attrs = tmp->mAttrsAndChildren.AttrCount();
2050 1990 : for (i = 0; i < attrs; i++) {
2051 1558 : const nsAttrName* name = tmp->mAttrsAndChildren.AttrNameAt(i);
2052 1558 : if (!name->IsAtom()) {
2053 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
2054 63 : "mAttrsAndChildren[i]->NodeInfo()");
2055 63 : cb.NoteNativeChild(name->NodeInfo(),
2056 126 : NS_CYCLE_COLLECTION_PARTICIPANT(NodeInfo));
2057 : }
2058 : }
2059 :
2060 432 : uint32_t kids = tmp->mAttrsAndChildren.ChildCount();
2061 1235 : for (i = 0; i < kids; i++) {
2062 803 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAttrsAndChildren[i]");
2063 803 : cb.NoteXPCOMChild(tmp->mAttrsAndChildren.GetSafeChildAt(i));
2064 : }
2065 : }
2066 :
2067 : // Traverse any DOM slots of interest.
2068 : {
2069 432 : nsDOMSlots *slots = tmp->GetExistingDOMSlots();
2070 432 : if (slots) {
2071 290 : slots->Traverse(cb, tmp->IsXULElement());
2072 : }
2073 : }
2074 432 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2075 :
2076 :
2077 20883 : NS_INTERFACE_MAP_BEGIN(FragmentOrElement)
2078 20883 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
2079 20099 : NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(FragmentOrElement)
2080 16785 : NS_INTERFACE_MAP_ENTRY(Element)
2081 14994 : NS_INTERFACE_MAP_ENTRY(nsIContent)
2082 7380 : NS_INTERFACE_MAP_ENTRY(nsINode)
2083 4259 : NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
2084 4244 : NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
2085 1613 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
2086 : new nsNodeSupportsWeakRefTearoff(this))
2087 : // DOM bindings depend on the identity pointer being the
2088 : // same as nsINode (which nsIContent inherits).
2089 1359 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
2090 514 : NS_INTERFACE_MAP_END
2091 :
2092 40755 : NS_IMPL_CYCLE_COLLECTING_ADDREF(FragmentOrElement)
2093 31949 : NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(FragmentOrElement,
2094 : nsNodeUtils::LastRelease(this))
2095 :
2096 : //----------------------------------------------------------------------
2097 :
2098 : nsresult
2099 337 : FragmentOrElement::CopyInnerTo(FragmentOrElement* aDst,
2100 : bool aPreallocateChildren)
2101 : {
2102 337 : nsresult rv = aDst->mAttrsAndChildren.EnsureCapacityToClone(mAttrsAndChildren,
2103 337 : aPreallocateChildren);
2104 337 : NS_ENSURE_SUCCESS(rv, rv);
2105 :
2106 337 : uint32_t i, count = mAttrsAndChildren.AttrCount();
2107 568 : for (i = 0; i < count; ++i) {
2108 231 : const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
2109 231 : const nsAttrValue* value = mAttrsAndChildren.AttrAt(i);
2110 462 : nsAutoString valStr;
2111 231 : value->ToString(valStr);
2112 462 : rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
2113 462 : name->GetPrefix(), valStr, false);
2114 231 : NS_ENSURE_SUCCESS(rv, rv);
2115 : }
2116 :
2117 337 : return NS_OK;
2118 : }
2119 :
2120 : const nsTextFragment*
2121 0 : FragmentOrElement::GetText()
2122 : {
2123 0 : return nullptr;
2124 : }
2125 :
2126 : uint32_t
2127 0 : FragmentOrElement::TextLength() const
2128 : {
2129 : // We can remove this assertion if it turns out to be useful to be able
2130 : // to depend on this returning 0
2131 0 : NS_NOTREACHED("called FragmentOrElement::TextLength");
2132 :
2133 0 : return 0;
2134 : }
2135 :
2136 : nsresult
2137 0 : FragmentOrElement::SetText(const char16_t* aBuffer, uint32_t aLength,
2138 : bool aNotify)
2139 : {
2140 0 : NS_ERROR("called FragmentOrElement::SetText");
2141 :
2142 0 : return NS_ERROR_FAILURE;
2143 : }
2144 :
2145 : nsresult
2146 0 : FragmentOrElement::AppendText(const char16_t* aBuffer, uint32_t aLength,
2147 : bool aNotify)
2148 : {
2149 0 : NS_ERROR("called FragmentOrElement::AppendText");
2150 :
2151 0 : return NS_ERROR_FAILURE;
2152 : }
2153 :
2154 : bool
2155 0 : FragmentOrElement::TextIsOnlyWhitespace()
2156 : {
2157 0 : return false;
2158 : }
2159 :
2160 : bool
2161 0 : FragmentOrElement::ThreadSafeTextIsOnlyWhitespace() const
2162 : {
2163 0 : return false;
2164 : }
2165 :
2166 : bool
2167 0 : FragmentOrElement::HasTextForTranslation()
2168 : {
2169 0 : return false;
2170 : }
2171 :
2172 : void
2173 0 : FragmentOrElement::AppendTextTo(nsAString& aResult)
2174 : {
2175 : // We can remove this assertion if it turns out to be useful to be able
2176 : // to depend on this appending nothing.
2177 0 : NS_NOTREACHED("called FragmentOrElement::TextLength");
2178 0 : }
2179 :
2180 : bool
2181 0 : FragmentOrElement::AppendTextTo(nsAString& aResult, const mozilla::fallible_t&)
2182 : {
2183 : // We can remove this assertion if it turns out to be useful to be able
2184 : // to depend on this appending nothing.
2185 0 : NS_NOTREACHED("called FragmentOrElement::TextLength");
2186 :
2187 0 : return false;
2188 : }
2189 :
2190 : uint32_t
2191 3780 : FragmentOrElement::GetChildCount() const
2192 : {
2193 3780 : return mAttrsAndChildren.ChildCount();
2194 : }
2195 :
2196 : nsIContent *
2197 1087 : FragmentOrElement::GetChildAt(uint32_t aIndex) const
2198 : {
2199 1087 : return mAttrsAndChildren.GetSafeChildAt(aIndex);
2200 : }
2201 :
2202 : nsIContent * const *
2203 1023 : FragmentOrElement::GetChildArray(uint32_t* aChildCount) const
2204 : {
2205 1023 : return mAttrsAndChildren.GetChildArray(aChildCount);
2206 : }
2207 :
2208 : int32_t
2209 729 : FragmentOrElement::IndexOf(const nsINode* aPossibleChild) const
2210 : {
2211 729 : return mAttrsAndChildren.IndexOfChild(aPossibleChild);
2212 : }
2213 :
2214 : static inline bool
2215 0 : IsVoidTag(nsIAtom* aTag)
2216 : {
2217 : static const nsIAtom* voidElements[] = {
2218 : nsGkAtoms::area, nsGkAtoms::base, nsGkAtoms::basefont,
2219 : nsGkAtoms::bgsound, nsGkAtoms::br, nsGkAtoms::col,
2220 : nsGkAtoms::embed, nsGkAtoms::frame,
2221 : nsGkAtoms::hr, nsGkAtoms::img, nsGkAtoms::input,
2222 : nsGkAtoms::keygen, nsGkAtoms::link, nsGkAtoms::meta,
2223 : nsGkAtoms::param, nsGkAtoms::source, nsGkAtoms::track,
2224 : nsGkAtoms::wbr
2225 0 : };
2226 :
2227 0 : static mozilla::BloomFilter<12, nsIAtom> sFilter;
2228 : static bool sInitialized = false;
2229 0 : if (!sInitialized) {
2230 0 : sInitialized = true;
2231 0 : for (uint32_t i = 0; i < ArrayLength(voidElements); ++i) {
2232 0 : sFilter.add(voidElements[i]);
2233 : }
2234 : }
2235 :
2236 0 : if (sFilter.mightContain(aTag)) {
2237 0 : for (uint32_t i = 0; i < ArrayLength(voidElements); ++i) {
2238 0 : if (aTag == voidElements[i]) {
2239 0 : return true;
2240 : }
2241 : }
2242 : }
2243 0 : return false;
2244 : }
2245 :
2246 : /* static */
2247 : bool
2248 0 : FragmentOrElement::IsHTMLVoid(nsIAtom* aLocalName)
2249 : {
2250 0 : return aLocalName && IsVoidTag(aLocalName);
2251 : }
2252 :
2253 : void
2254 0 : FragmentOrElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
2255 : {
2256 0 : aMarkup.Truncate();
2257 :
2258 0 : nsIDocument* doc = OwnerDoc();
2259 0 : if (IsInHTMLDocument()) {
2260 0 : nsContentUtils::SerializeNodeToMarkup(this, !aIncludeSelf, aMarkup);
2261 0 : return;
2262 : }
2263 :
2264 0 : nsAutoString contentType;
2265 0 : doc->GetContentType(contentType);
2266 0 : bool tryToCacheEncoder = !aIncludeSelf;
2267 :
2268 0 : nsCOMPtr<nsIDocumentEncoder> docEncoder = doc->GetCachedEncoder();
2269 0 : if (!docEncoder) {
2270 : docEncoder =
2271 0 : do_CreateInstance(PromiseFlatCString(
2272 0 : nsDependentCString(NS_DOC_ENCODER_CONTRACTID_BASE) +
2273 0 : NS_ConvertUTF16toUTF8(contentType)
2274 0 : ).get());
2275 : }
2276 0 : if (!docEncoder) {
2277 : // This could be some type for which we create a synthetic document. Try
2278 : // again as XML
2279 0 : contentType.AssignLiteral("application/xml");
2280 0 : docEncoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "application/xml");
2281 : // Don't try to cache the encoder since it would point to a different
2282 : // contentType once it has been reinitialized.
2283 0 : tryToCacheEncoder = false;
2284 : }
2285 :
2286 0 : NS_ENSURE_TRUE_VOID(docEncoder);
2287 :
2288 : uint32_t flags = nsIDocumentEncoder::OutputEncodeBasicEntities |
2289 : // Output DOM-standard newlines
2290 : nsIDocumentEncoder::OutputLFLineBreak |
2291 : // Don't do linebreaking that's not present in
2292 : // the source
2293 : nsIDocumentEncoder::OutputRaw |
2294 : // Only check for mozdirty when necessary (bug 599983)
2295 0 : nsIDocumentEncoder::OutputIgnoreMozDirty;
2296 :
2297 0 : if (IsEditable()) {
2298 0 : nsCOMPtr<Element> elem = do_QueryInterface(this);
2299 0 : TextEditor* textEditor = elem ? elem->GetTextEditorInternal() : nullptr;
2300 0 : if (textEditor && textEditor->OutputsMozDirty()) {
2301 0 : flags &= ~nsIDocumentEncoder::OutputIgnoreMozDirty;
2302 : }
2303 : }
2304 :
2305 0 : DebugOnly<nsresult> rv = docEncoder->NativeInit(doc, contentType, flags);
2306 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
2307 :
2308 0 : if (aIncludeSelf) {
2309 0 : docEncoder->SetNativeNode(this);
2310 : } else {
2311 0 : docEncoder->SetNativeContainerNode(this);
2312 : }
2313 0 : rv = docEncoder->EncodeToString(aMarkup);
2314 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
2315 0 : if (tryToCacheEncoder) {
2316 0 : doc->SetCachedEncoder(docEncoder.forget());
2317 : }
2318 : }
2319 :
2320 : static bool
2321 0 : ContainsMarkup(const nsAString& aStr)
2322 : {
2323 : // Note: we can't use FindCharInSet because null is one of the characters we
2324 : // want to search for.
2325 0 : const char16_t* start = aStr.BeginReading();
2326 0 : const char16_t* end = aStr.EndReading();
2327 :
2328 0 : while (start != end) {
2329 0 : char16_t c = *start;
2330 0 : if (c == char16_t('<') ||
2331 0 : c == char16_t('&') ||
2332 0 : c == char16_t('\r') ||
2333 : c == char16_t('\0')) {
2334 0 : return true;
2335 : }
2336 0 : ++start;
2337 : }
2338 :
2339 0 : return false;
2340 : }
2341 :
2342 : void
2343 0 : FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError)
2344 : {
2345 0 : FragmentOrElement* target = this;
2346 : // Handle template case.
2347 0 : if (nsNodeUtils::IsTemplateElement(target)) {
2348 : DocumentFragment* frag =
2349 0 : static_cast<HTMLTemplateElement*>(target)->Content();
2350 0 : MOZ_ASSERT(frag);
2351 0 : target = frag;
2352 : }
2353 :
2354 : // Fast-path for strings with no markup. Limit this to short strings, to
2355 : // avoid ContainsMarkup taking too long. The choice for 100 is based on
2356 : // gut feeling.
2357 : //
2358 : // Don't do this for elements with a weird parser insertion mode, for
2359 : // instance setting innerHTML = "" on a <html> element should add the
2360 : // optional <head> and <body> elements.
2361 0 : if (!target->HasWeirdParserInsertionMode() &&
2362 0 : aInnerHTML.Length() < 100 && !ContainsMarkup(aInnerHTML)) {
2363 0 : aError = nsContentUtils::SetNodeTextContent(target, aInnerHTML, false);
2364 0 : return;
2365 : }
2366 :
2367 0 : nsIDocument* doc = target->OwnerDoc();
2368 :
2369 : // Batch possible DOMSubtreeModified events.
2370 0 : mozAutoSubtreeModified subtree(doc, nullptr);
2371 :
2372 0 : target->FireNodeRemovedForChildren();
2373 :
2374 : // Needed when innerHTML is used in combination with contenteditable
2375 0 : mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
2376 :
2377 : // Remove childnodes.
2378 0 : uint32_t childCount = target->GetChildCount();
2379 0 : nsAutoMutationBatch mb(target, true, false);
2380 0 : for (uint32_t i = 0; i < childCount; ++i) {
2381 0 : target->RemoveChildAt(0, true);
2382 : }
2383 0 : mb.RemovalDone();
2384 :
2385 0 : nsAutoScriptLoaderDisabler sld(doc);
2386 :
2387 0 : nsIAtom* contextLocalName = NodeInfo()->NameAtom();
2388 0 : int32_t contextNameSpaceID = GetNameSpaceID();
2389 :
2390 0 : ShadowRoot* shadowRoot = ShadowRoot::FromNode(this);
2391 0 : if (shadowRoot) {
2392 : // Fix up the context to be the host of the ShadowRoot.
2393 0 : contextLocalName = shadowRoot->GetHost()->NodeInfo()->NameAtom();
2394 0 : contextNameSpaceID = shadowRoot->GetHost()->GetNameSpaceID();
2395 : }
2396 :
2397 0 : if (doc->IsHTMLDocument()) {
2398 0 : int32_t oldChildCount = target->GetChildCount();
2399 0 : aError = nsContentUtils::ParseFragmentHTML(aInnerHTML,
2400 : target,
2401 : contextLocalName,
2402 : contextNameSpaceID,
2403 0 : doc->GetCompatibilityMode() ==
2404 : eCompatibility_NavQuirks,
2405 0 : true);
2406 0 : mb.NodesAdded();
2407 : // HTML5 parser has notified, but not fired mutation events.
2408 : nsContentUtils::FireMutationEventsForDirectParsing(doc, target,
2409 0 : oldChildCount);
2410 : } else {
2411 : RefPtr<DocumentFragment> df =
2412 0 : nsContentUtils::CreateContextualFragment(target, aInnerHTML, true, aError);
2413 0 : if (!aError.Failed()) {
2414 : // Suppress assertion about node removal mutation events that can't have
2415 : // listeners anyway, because no one has had the chance to register mutation
2416 : // listeners on the fragment that comes from the parser.
2417 0 : nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
2418 :
2419 0 : static_cast<nsINode*>(target)->AppendChild(*df, aError);
2420 0 : mb.NodesAdded();
2421 : }
2422 : }
2423 : }
2424 :
2425 : nsINode::nsSlots*
2426 275 : FragmentOrElement::CreateSlots()
2427 : {
2428 275 : return new nsDOMSlots();
2429 : }
2430 :
2431 : void
2432 4 : FragmentOrElement::FireNodeRemovedForChildren()
2433 : {
2434 4 : nsIDocument* doc = OwnerDoc();
2435 : // Optimize the common case
2436 4 : if (!nsContentUtils::
2437 4 : HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
2438 4 : return;
2439 : }
2440 :
2441 0 : nsCOMPtr<nsIDocument> owningDoc = doc;
2442 :
2443 0 : nsCOMPtr<nsINode> child;
2444 0 : for (child = GetFirstChild();
2445 0 : child && child->GetParentNode() == this;
2446 0 : child = child->GetNextSibling()) {
2447 0 : nsContentUtils::MaybeFireNodeRemoved(child, this, doc);
2448 : }
2449 : }
2450 :
2451 : size_t
2452 130 : FragmentOrElement::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
2453 : {
2454 130 : size_t n = 0;
2455 130 : n += nsIContent::SizeOfExcludingThis(aMallocSizeOf);
2456 130 : n += mAttrsAndChildren.SizeOfExcludingThis(aMallocSizeOf);
2457 :
2458 130 : nsDOMSlots* slots = GetExistingDOMSlots();
2459 130 : if (slots) {
2460 5 : n += slots->SizeOfIncludingThis(aMallocSizeOf);
2461 : }
2462 :
2463 130 : return n;
2464 : }
2465 :
2466 : void
2467 0 : FragmentOrElement::SetIsElementInStyleScopeFlagOnSubtree(bool aInStyleScope)
2468 : {
2469 0 : if (aInStyleScope && IsElementInStyleScope()) {
2470 0 : return;
2471 : }
2472 :
2473 0 : if (IsElement()) {
2474 0 : SetIsElementInStyleScope(aInStyleScope);
2475 0 : SetIsElementInStyleScopeFlagOnShadowTree(aInStyleScope);
2476 : }
2477 :
2478 0 : nsIContent* n = GetNextNode(this);
2479 0 : while (n) {
2480 0 : if (n->IsElementInStyleScope()) {
2481 0 : n = n->GetNextNonChildNode(this);
2482 : } else {
2483 0 : if (n->IsElement()) {
2484 0 : n->SetIsElementInStyleScope(aInStyleScope);
2485 0 : n->AsElement()->SetIsElementInStyleScopeFlagOnShadowTree(aInStyleScope);
2486 : }
2487 0 : n = n->GetNextNode(this);
2488 : }
2489 : }
2490 : }
2491 :
2492 : void
2493 4709 : FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
2494 : {
2495 4709 : NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
2496 : "on a non-Element is useless");
2497 4709 : ShadowRoot* shadowRoot = GetShadowRoot();
2498 4709 : while (shadowRoot) {
2499 0 : shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
2500 0 : shadowRoot = shadowRoot->GetOlderShadowRoot();
2501 : }
2502 4709 : }
|