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/dom/ElementInlines.h"
14 :
15 : #include "AnimationCommon.h"
16 : #include "mozilla/DebugOnly.h"
17 : #include "mozilla/dom/Animation.h"
18 : #include "mozilla/dom/Attr.h"
19 : #include "mozilla/dom/Grid.h"
20 : #include "nsDOMAttributeMap.h"
21 : #include "nsIAtom.h"
22 : #include "nsIContentInlines.h"
23 : #include "mozilla/dom/NodeInfo.h"
24 : #include "nsIDocumentInlines.h"
25 : #include "mozilla/dom/DocumentTimeline.h"
26 : #include "nsIDOMNodeList.h"
27 : #include "nsIDOMDocument.h"
28 : #include "nsIContentIterator.h"
29 : #include "nsFocusManager.h"
30 : #include "nsFrameManager.h"
31 : #include "nsILinkHandler.h"
32 : #include "nsIScriptGlobalObject.h"
33 : #include "nsIURL.h"
34 : #include "nsContainerFrame.h"
35 : #include "nsIAnonymousContentCreator.h"
36 : #include "nsIPresShell.h"
37 : #include "nsPresContext.h"
38 : #include "nsStyleConsts.h"
39 : #include "nsString.h"
40 : #include "nsUnicharUtils.h"
41 : #include "nsIDOMEvent.h"
42 : #include "nsDOMCID.h"
43 : #include "nsIServiceManager.h"
44 : #include "nsIDOMCSSStyleDeclaration.h"
45 : #include "nsDOMCSSAttrDeclaration.h"
46 : #include "nsNameSpaceManager.h"
47 : #include "nsContentList.h"
48 : #include "nsVariant.h"
49 : #include "nsDOMTokenList.h"
50 : #include "nsXBLPrototypeBinding.h"
51 : #include "nsError.h"
52 : #include "nsDOMString.h"
53 : #include "nsIScriptSecurityManager.h"
54 : #include "nsIDOMMutationEvent.h"
55 : #include "mozilla/dom/AnimatableBinding.h"
56 : #include "mozilla/dom/HTMLDivElement.h"
57 : #include "mozilla/dom/HTMLSpanElement.h"
58 : #include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
59 : #include "mozilla/AnimationComparator.h"
60 : #include "mozilla/AsyncEventDispatcher.h"
61 : #include "mozilla/ContentEvents.h"
62 : #include "mozilla/DeclarationBlockInlines.h"
63 : #include "mozilla/EffectSet.h"
64 : #include "mozilla/EventDispatcher.h"
65 : #include "mozilla/EventListenerManager.h"
66 : #include "mozilla/EventStateManager.h"
67 : #include "mozilla/EventStates.h"
68 : #include "mozilla/InternalMutationEvent.h"
69 : #include "mozilla/MouseEvents.h"
70 : #include "mozilla/TextEditor.h"
71 : #include "mozilla/TextEvents.h"
72 : #include "nsNodeUtils.h"
73 : #include "mozilla/dom/DirectionalityUtils.h"
74 : #include "nsDocument.h"
75 : #include "nsAttrValueOrString.h"
76 : #include "nsAttrValueInlines.h"
77 : #include "nsCSSPseudoElements.h"
78 : #ifdef MOZ_XUL
79 : #include "nsXULElement.h"
80 : #endif /* MOZ_XUL */
81 : #include "nsSVGElement.h"
82 : #include "nsFrameSelection.h"
83 : #ifdef DEBUG
84 : #include "nsRange.h"
85 : #endif
86 :
87 : #include "nsBindingManager.h"
88 : #include "nsXBLBinding.h"
89 : #include "nsPIDOMWindow.h"
90 : #include "nsPIBoxObject.h"
91 : #include "mozilla/dom/DOMRect.h"
92 : #include "nsSVGUtils.h"
93 : #include "nsLayoutUtils.h"
94 : #include "nsGkAtoms.h"
95 : #include "nsContentUtils.h"
96 : #include "ChildIterator.h"
97 :
98 : #include "nsIDOMEventListener.h"
99 : #include "nsIWebNavigation.h"
100 : #include "nsIBaseWindow.h"
101 : #include "nsIWidget.h"
102 :
103 : #include "nsNodeInfoManager.h"
104 : #include "nsICategoryManager.h"
105 : #include "nsIDOMDocumentType.h"
106 : #include "nsGenericHTMLElement.h"
107 : #include "nsContentCreatorFunctions.h"
108 : #include "nsIControllers.h"
109 : #include "nsView.h"
110 : #include "nsViewManager.h"
111 : #include "nsIScrollableFrame.h"
112 : #include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */
113 : #include "nsCSSRuleProcessor.h"
114 : #include "nsRuleProcessorData.h"
115 : #include "nsTextNode.h"
116 :
117 : #ifdef MOZ_XUL
118 : #include "nsIXULDocument.h"
119 : #endif /* MOZ_XUL */
120 :
121 : #include "nsCycleCollectionParticipant.h"
122 : #include "nsCCUncollectableMarker.h"
123 :
124 : #include "mozAutoDocUpdate.h"
125 :
126 : #include "nsCSSParser.h"
127 : #include "nsDOMMutationObserver.h"
128 : #include "nsWrapperCacheInlines.h"
129 : #include "xpcpublic.h"
130 : #include "nsIScriptError.h"
131 : #include "mozilla/Telemetry.h"
132 :
133 : #include "mozilla/CORSMode.h"
134 : #include "mozilla/dom/ShadowRoot.h"
135 : #include "mozilla/dom/NodeListBinding.h"
136 :
137 : #include "nsStyledElement.h"
138 : #include "nsXBLService.h"
139 : #include "nsITextControlElement.h"
140 : #include "nsITextControlFrame.h"
141 : #include "nsISupportsImpl.h"
142 : #include "mozilla/dom/CSSPseudoElement.h"
143 : #include "mozilla/dom/DocumentFragment.h"
144 : #include "mozilla/dom/KeyframeEffect.h"
145 : #include "mozilla/dom/KeyframeEffectBinding.h"
146 : #include "mozilla/dom/WindowBinding.h"
147 : #include "mozilla/dom/ElementBinding.h"
148 : #include "mozilla/dom/VRDisplay.h"
149 : #include "mozilla/IntegerPrintfMacros.h"
150 : #include "mozilla/Preferences.h"
151 : #include "nsComputedDOMStyle.h"
152 : #include "nsDOMStringMap.h"
153 : #include "DOMIntersectionObserver.h"
154 :
155 : #include "nsISpeculativeConnect.h"
156 :
157 : #include "DOMMatrix.h"
158 :
159 : using namespace mozilla;
160 : using namespace mozilla::dom;
161 :
162 : //
163 : // Verify sizes of elements on 64-bit platforms. This should catch most memory
164 : // regressions, and is easy to verify locally since most developers are on
165 : // 64-bit machines. We use a template rather than a direct static assert so
166 : // that the error message actually displays the sizes.
167 : //
168 :
169 : // We need different numbers on certain build types to deal with the owning
170 : // thread pointer that comes with the non-threadsafe refcount on
171 : // FragmentOrElement.
172 : #ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
173 : #define EXTRA_DOM_ELEMENT_BYTES 8
174 : #else
175 : #define EXTRA_DOM_ELEMENT_BYTES 0
176 : #endif
177 :
178 : #define ASSERT_ELEMENT_SIZE(type, opt_size) \
179 : template<int a, int b> struct Check##type##Size \
180 : { \
181 : static_assert(sizeof(void*) != 8 || a == b, "DOM size changed"); \
182 : }; \
183 : Check##type##Size<sizeof(type), opt_size + EXTRA_DOM_ELEMENT_BYTES> g##type##CES;
184 :
185 : // Note that mozjemalloc uses a 16 byte quantum, so 128 is a bin/bucket size.
186 : ASSERT_ELEMENT_SIZE(Element, 120);
187 : ASSERT_ELEMENT_SIZE(HTMLDivElement, 128);
188 : ASSERT_ELEMENT_SIZE(HTMLSpanElement, 128);
189 :
190 : #undef ASSERT_ELEMENT_SIZE
191 : #undef EXTRA_DOM_ELEMENT_BYTES
192 :
193 : nsIAtom*
194 75000 : nsIContent::DoGetID() const
195 : {
196 75000 : MOZ_ASSERT(HasID(), "Unexpected call");
197 75000 : MOZ_ASSERT(IsElement(), "Only elements can have IDs");
198 :
199 75000 : return AsElement()->GetParsedAttr(nsGkAtoms::id)->GetAtomValue();
200 : }
201 :
202 : const nsAttrValue*
203 18576 : Element::DoGetClasses() const
204 : {
205 18576 : MOZ_ASSERT(MayHaveClass(), "Unexpected call");
206 18576 : if (IsSVGElement()) {
207 : const nsAttrValue* animClass =
208 112 : static_cast<const nsSVGElement*>(this)->GetAnimatedClassName();
209 112 : if (animClass) {
210 0 : return animClass;
211 : }
212 : }
213 :
214 18576 : return GetParsedAttr(nsGkAtoms::_class);
215 : }
216 :
217 : NS_IMETHODIMP
218 4495 : Element::QueryInterface(REFNSIID aIID, void** aInstancePtr)
219 : {
220 4495 : NS_ASSERTION(aInstancePtr,
221 : "QueryInterface requires a non-NULL destination!");
222 4495 : nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr);
223 4495 : if (NS_SUCCEEDED(rv)) {
224 4285 : return NS_OK;
225 : }
226 :
227 : // Give the binding manager a chance to get an interface for this element.
228 210 : return OwnerDoc()->BindingManager()->GetBindingImplementation(this, aIID,
229 210 : aInstancePtr);
230 : }
231 :
232 : EventStates
233 5711 : Element::IntrinsicState() const
234 : {
235 5711 : return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE :
236 5711 : NS_EVENT_STATE_MOZ_READONLY;
237 : }
238 :
239 : void
240 45 : Element::NotifyStateChange(EventStates aStates)
241 : {
242 45 : nsIDocument* doc = GetComposedDoc();
243 45 : if (doc) {
244 90 : nsAutoScriptBlocker scriptBlocker;
245 45 : doc->ContentStateChanged(this, aStates);
246 : }
247 45 : }
248 :
249 : void
250 0 : Element::UpdateLinkState(EventStates aState)
251 : {
252 0 : MOZ_ASSERT(!aState.HasAtLeastOneOfStates(~(NS_EVENT_STATE_VISITED |
253 : NS_EVENT_STATE_UNVISITED)),
254 : "Unexpected link state bits");
255 : mState =
256 0 : (mState & ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) |
257 0 : aState;
258 0 : }
259 :
260 : void
261 5711 : Element::UpdateState(bool aNotify)
262 : {
263 5711 : EventStates oldState = mState;
264 5711 : mState = IntrinsicState() | (oldState & EXTERNALLY_MANAGED_STATES);
265 5711 : if (aNotify) {
266 616 : EventStates changedStates = oldState ^ mState;
267 616 : if (!changedStates.IsEmpty()) {
268 10 : nsIDocument* doc = GetComposedDoc();
269 10 : if (doc) {
270 20 : nsAutoScriptBlocker scriptBlocker;
271 10 : doc->ContentStateChanged(this, changedStates);
272 : }
273 : }
274 : }
275 5711 : }
276 :
277 : void
278 567 : nsIContent::UpdateEditableState(bool aNotify)
279 : {
280 : // Guaranteed to be non-element content
281 567 : NS_ASSERTION(!IsElement(), "What happened here?");
282 567 : nsIContent *parent = GetParent();
283 :
284 : // Skip over unknown native anonymous content to avoid setting a flag we
285 : // can't clear later
286 567 : bool isUnknownNativeAnon = false;
287 567 : if (IsInNativeAnonymousSubtree()) {
288 15 : isUnknownNativeAnon = true;
289 30 : nsCOMPtr<nsIContent> root = this;
290 45 : while (root && !root->IsRootOfNativeAnonymousSubtree()) {
291 15 : root = root->GetParent();
292 : }
293 : // root should always be true here, but isn't -- bug 999416
294 15 : if (root) {
295 15 : nsIFrame* rootFrame = root->GetPrimaryFrame();
296 15 : if (rootFrame) {
297 1 : nsContainerFrame* parentFrame = rootFrame->GetParent();
298 1 : nsITextControlFrame* textCtrl = do_QueryFrame(parentFrame);
299 1 : isUnknownNativeAnon = !textCtrl;
300 : }
301 : }
302 : }
303 :
304 572 : SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE) &&
305 572 : !isUnknownNativeAnon);
306 567 : }
307 :
308 : void
309 1062 : Element::UpdateEditableState(bool aNotify)
310 : {
311 1062 : nsIContent *parent = GetParent();
312 :
313 1062 : SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
314 1062 : if (aNotify) {
315 0 : UpdateState(aNotify);
316 : } else {
317 : // Avoid calling UpdateState in this very common case, because
318 : // this gets called for pretty much every single element on
319 : // insertion into the document and UpdateState can be slow for
320 : // some kinds of elements even when not notifying.
321 1062 : if (IsEditable()) {
322 2 : RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
323 2 : AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
324 : } else {
325 1060 : RemoveStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
326 1060 : AddStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
327 : }
328 : }
329 1062 : }
330 :
331 : int32_t
332 0 : Element::TabIndex()
333 : {
334 0 : const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::tabindex);
335 0 : if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
336 0 : return attrVal->GetIntegerValue();
337 : }
338 :
339 0 : return TabIndexDefault();
340 : }
341 :
342 : void
343 2 : Element::Focus(mozilla::ErrorResult& aError)
344 : {
345 4 : nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(this);
346 2 : nsFocusManager* fm = nsFocusManager::GetFocusManager();
347 : // Also other browsers seem to have the hack to not re-focus (and flush) when
348 : // the element is already focused.
349 2 : if (fm && domElement) {
350 2 : if (fm->CanSkipFocus(this)) {
351 0 : fm->NeedsFlushBeforeEventHandling(this);
352 : } else {
353 2 : aError = fm->SetFocus(domElement, 0);
354 : }
355 : }
356 2 : }
357 :
358 : void
359 0 : Element::SetTabIndex(int32_t aTabIndex, mozilla::ErrorResult& aError)
360 : {
361 0 : nsAutoString value;
362 0 : value.AppendInt(aTabIndex);
363 :
364 0 : SetAttr(nsGkAtoms::tabindex, value, aError);
365 0 : }
366 :
367 : void
368 0 : Element::Blur(mozilla::ErrorResult& aError)
369 : {
370 0 : if (!ShouldBlur(this)) {
371 0 : return;
372 : }
373 :
374 0 : nsIDocument* doc = GetComposedDoc();
375 0 : if (!doc) {
376 0 : return;
377 : }
378 :
379 0 : nsPIDOMWindowOuter* win = doc->GetWindow();
380 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
381 0 : if (win && fm) {
382 0 : aError = fm->ClearFocus(win);
383 : }
384 : }
385 :
386 : EventStates
387 0 : Element::StyleStateFromLocks() const
388 : {
389 0 : StyleStateLocks locksAndValues = LockedStyleStates();
390 0 : EventStates locks = locksAndValues.mLocks;
391 0 : EventStates values = locksAndValues.mValues;
392 0 : EventStates state = (mState & ~locks) | (locks & values);
393 :
394 0 : if (state.HasState(NS_EVENT_STATE_VISITED)) {
395 0 : return state & ~NS_EVENT_STATE_UNVISITED;
396 : }
397 0 : if (state.HasState(NS_EVENT_STATE_UNVISITED)) {
398 0 : return state & ~NS_EVENT_STATE_VISITED;
399 : }
400 :
401 0 : return state;
402 : }
403 :
404 : Element::StyleStateLocks
405 0 : Element::LockedStyleStates() const
406 : {
407 : StyleStateLocks* locks =
408 0 : static_cast<StyleStateLocks*>(GetProperty(nsGkAtoms::lockedStyleStates));
409 0 : if (locks) {
410 0 : return *locks;
411 : }
412 0 : return StyleStateLocks();
413 : }
414 :
415 : void
416 0 : Element::NotifyStyleStateChange(EventStates aStates)
417 : {
418 0 : nsIDocument* doc = GetComposedDoc();
419 0 : if (doc) {
420 0 : nsIPresShell *presShell = doc->GetShell();
421 0 : if (presShell) {
422 0 : nsAutoScriptBlocker scriptBlocker;
423 0 : presShell->ContentStateChanged(doc, this, aStates);
424 : }
425 : }
426 0 : }
427 :
428 : void
429 0 : Element::LockStyleStates(EventStates aStates, bool aEnabled)
430 : {
431 0 : StyleStateLocks* locks = new StyleStateLocks(LockedStyleStates());
432 :
433 0 : locks->mLocks |= aStates;
434 0 : if (aEnabled) {
435 0 : locks->mValues |= aStates;
436 : } else {
437 0 : locks->mValues &= ~aStates;
438 : }
439 :
440 0 : if (aStates.HasState(NS_EVENT_STATE_VISITED)) {
441 0 : locks->mLocks &= ~NS_EVENT_STATE_UNVISITED;
442 : }
443 0 : if (aStates.HasState(NS_EVENT_STATE_UNVISITED)) {
444 0 : locks->mLocks &= ~NS_EVENT_STATE_VISITED;
445 : }
446 :
447 0 : SetProperty(nsGkAtoms::lockedStyleStates, locks,
448 0 : nsINode::DeleteProperty<StyleStateLocks>);
449 0 : SetHasLockedStyleStates();
450 :
451 0 : NotifyStyleStateChange(aStates);
452 0 : }
453 :
454 : void
455 0 : Element::UnlockStyleStates(EventStates aStates)
456 : {
457 0 : StyleStateLocks* locks = new StyleStateLocks(LockedStyleStates());
458 :
459 0 : locks->mLocks &= ~aStates;
460 :
461 0 : if (locks->mLocks.IsEmpty()) {
462 0 : DeleteProperty(nsGkAtoms::lockedStyleStates);
463 0 : ClearHasLockedStyleStates();
464 : delete locks;
465 : }
466 : else {
467 0 : SetProperty(nsGkAtoms::lockedStyleStates, locks,
468 0 : nsINode::DeleteProperty<StyleStateLocks>);
469 : }
470 :
471 0 : NotifyStyleStateChange(aStates);
472 0 : }
473 :
474 : void
475 0 : Element::ClearStyleStateLocks()
476 : {
477 0 : StyleStateLocks locks = LockedStyleStates();
478 :
479 0 : DeleteProperty(nsGkAtoms::lockedStyleStates);
480 0 : ClearHasLockedStyleStates();
481 :
482 0 : NotifyStyleStateChange(locks.mLocks);
483 0 : }
484 :
485 : bool
486 133 : Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
487 : {
488 : // If we have a frame the frame has already loaded the binding. And
489 : // otherwise, don't do anything else here unless we're dealing with
490 : // XUL or an HTML element that may have a plugin-related overlay
491 : // (i.e. object, embed, or applet).
492 142 : bool isXULorPluginElement = (IsXULElement() ||
493 18 : IsHTMLElement(nsGkAtoms::object) ||
494 151 : IsHTMLElement(nsGkAtoms::embed) ||
495 142 : IsHTMLElement(nsGkAtoms::applet));
496 266 : nsCOMPtr<nsIPresShell> shell = aDocument->GetShell();
497 133 : if (!shell || GetPrimaryFrame() || !isXULorPluginElement) {
498 36 : *aResult = nullptr;
499 36 : return true;
500 : }
501 :
502 : // Get the computed -moz-binding directly from the style context
503 : RefPtr<nsStyleContext> sc =
504 194 : nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr, shell);
505 97 : NS_ENSURE_TRUE(sc, false);
506 :
507 97 : NS_IF_ADDREF(*aResult = sc->StyleDisplay()->mBinding);
508 97 : return true;
509 : }
510 :
511 : JSObject*
512 395 : Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
513 : {
514 790 : JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
515 790 : JS::Rooted<JSObject*> customProto(aCx);
516 :
517 395 : if (!givenProto) {
518 : // Custom element prototype swizzling.
519 395 : CustomElementData* data = GetCustomElementData();
520 395 : if (data) {
521 : // If this is a registered custom element then fix the prototype.
522 0 : nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
523 0 : data->mType, &customProto);
524 0 : if (customProto &&
525 0 : NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) {
526 : // Just go ahead and create with the right proto up front. Set
527 : // customProto to null to flag that we don't need to do any post-facto
528 : // proto fixups here.
529 0 : givenProto = customProto;
530 0 : customProto = nullptr;
531 : }
532 : }
533 : }
534 :
535 790 : JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, givenProto));
536 395 : if (!obj) {
537 0 : return nullptr;
538 : }
539 :
540 395 : if (customProto) {
541 : // We want to set the custom prototype in the compartment where it was
542 : // registered. In the case that |obj| and |prototype| are in different
543 : // compartments, this will set the prototype on the |obj|'s wrapper and
544 : // thus only visible in the wrapper's compartment, since we know obj's
545 : // principal does not subsume customProto's in this case.
546 0 : JSAutoCompartment ac(aCx, customProto);
547 0 : JS::Rooted<JSObject*> wrappedObj(aCx, obj);
548 0 : if (!JS_WrapObject(aCx, &wrappedObj) ||
549 0 : !JS_SetPrototype(aCx, wrappedObj, customProto)) {
550 0 : return nullptr;
551 : }
552 : }
553 :
554 : nsIDocument* doc;
555 395 : if (HasFlag(NODE_FORCE_XBL_BINDINGS)) {
556 2 : doc = OwnerDoc();
557 : }
558 : else {
559 393 : doc = GetComposedDoc();
560 : }
561 :
562 395 : if (!doc) {
563 : // There's no baseclass that cares about this call so we just
564 : // return here.
565 57 : return obj;
566 : }
567 :
568 : // We must ensure that the XBL Binding is installed before we hand
569 : // back this object.
570 :
571 338 : if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) && GetXBLBinding()) {
572 : // There's already a binding for this element so nothing left to
573 : // be done here.
574 :
575 : // In theory we could call ExecuteAttachedHandler here when it's safe to
576 : // run script if we also removed the binding from the PAQ queue, but that
577 : // seems like a scary change that would mosly just add more
578 : // inconsistencies.
579 205 : return obj;
580 : }
581 :
582 : // Make sure the style context goes away _before_ we load the binding
583 : // since that can destroy the relevant presshell.
584 :
585 : {
586 : // Make a scope so that ~nsRefPtr can GC before returning obj.
587 266 : RefPtr<css::URLValue> bindingURL;
588 133 : bool ok = GetBindingURL(doc, getter_AddRefs(bindingURL));
589 133 : if (!ok) {
590 0 : dom::Throw(aCx, NS_ERROR_FAILURE);
591 0 : return nullptr;
592 : }
593 :
594 133 : if (bindingURL) {
595 68 : nsCOMPtr<nsIURI> uri = bindingURL->GetURI();
596 68 : nsCOMPtr<nsIPrincipal> principal = bindingURL->mExtraData->GetPrincipal();
597 :
598 : // We have a binding that must be installed.
599 : bool dummy;
600 :
601 34 : nsXBLService* xblService = nsXBLService::GetInstance();
602 34 : if (!xblService) {
603 0 : dom::Throw(aCx, NS_ERROR_NOT_AVAILABLE);
604 0 : return nullptr;
605 : }
606 :
607 68 : RefPtr<nsXBLBinding> binding;
608 68 : xblService->LoadBindings(this, uri, principal, getter_AddRefs(binding),
609 34 : &dummy);
610 :
611 34 : if (binding) {
612 34 : if (nsContentUtils::IsSafeToRunScript()) {
613 34 : binding->ExecuteAttachedHandler();
614 : } else {
615 0 : nsContentUtils::AddScriptRunner(
616 0 : NewRunnableMethod("nsXBLBinding::ExecuteAttachedHandler",
617 : binding,
618 0 : &nsXBLBinding::ExecuteAttachedHandler));
619 : }
620 : }
621 : }
622 : }
623 :
624 133 : return obj;
625 : }
626 :
627 : /* virtual */
628 : nsINode*
629 170 : Element::GetScopeChainParent() const
630 : {
631 170 : return OwnerDoc();
632 : }
633 :
634 : nsDOMTokenList*
635 8 : Element::ClassList()
636 : {
637 8 : Element::nsDOMSlots* slots = DOMSlots();
638 :
639 8 : if (!slots->mClassList) {
640 8 : slots->mClassList = new nsDOMTokenList(this, nsGkAtoms::_class);
641 : }
642 :
643 8 : return slots->mClassList;
644 : }
645 :
646 : void
647 0 : Element::GetAttributeNames(nsTArray<nsString>& aResult)
648 : {
649 0 : uint32_t count = mAttrsAndChildren.AttrCount();
650 0 : for (uint32_t i = 0; i < count; ++i) {
651 0 : const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
652 0 : name->GetQualifiedName(*aResult.AppendElement());
653 : }
654 0 : }
655 :
656 : already_AddRefed<nsIHTMLCollection>
657 1 : Element::GetElementsByTagName(const nsAString& aLocalName)
658 : {
659 1 : return NS_GetContentList(this, kNameSpaceID_Unknown, aLocalName);
660 : }
661 :
662 : nsIFrame*
663 0 : Element::GetStyledFrame()
664 : {
665 0 : nsIFrame *frame = GetPrimaryFrame(FlushType::Layout);
666 0 : return frame ? nsLayoutUtils::GetStyleFrame(frame) : nullptr;
667 : }
668 :
669 : nsIScrollableFrame*
670 2 : Element::GetScrollFrame(nsIFrame **aStyledFrame, FlushType aFlushType)
671 : {
672 : // it isn't clear what to return for SVG nodes, so just return nothing
673 2 : if (IsSVGElement()) {
674 0 : if (aStyledFrame) {
675 0 : *aStyledFrame = nullptr;
676 : }
677 0 : return nullptr;
678 : }
679 :
680 : // Inline version of GetStyledFrame to use the given FlushType.
681 2 : nsIFrame* frame = GetPrimaryFrame(aFlushType);
682 2 : if (frame) {
683 2 : frame = nsLayoutUtils::GetStyleFrame(frame);
684 : }
685 :
686 2 : if (aStyledFrame) {
687 0 : *aStyledFrame = frame;
688 : }
689 2 : if (frame) {
690 : // menu frames implement GetScrollTargetFrame but we don't want
691 : // to use it here. Similar for comboboxes.
692 2 : LayoutFrameType type = frame->Type();
693 2 : if (type != LayoutFrameType::Menu &&
694 : type != LayoutFrameType::ComboboxControl) {
695 2 : nsIScrollableFrame *scrollFrame = frame->GetScrollTargetFrame();
696 2 : if (scrollFrame) {
697 2 : MOZ_ASSERT(!OwnerDoc()->IsScrollingElement(this),
698 : "How can we have a scrollframe if we're the "
699 : "scrollingElement for our document?");
700 2 : return scrollFrame;
701 : }
702 : }
703 : }
704 :
705 0 : nsIDocument* doc = OwnerDoc();
706 : // Note: This IsScrollingElement() call can flush frames, if we're the body of
707 : // a quirks mode document.
708 0 : bool isScrollingElement = OwnerDoc()->IsScrollingElement(this);
709 : // Now reget *aStyledFrame if the caller asked for it, because that frame
710 : // flush can kill it.
711 0 : if (aStyledFrame) {
712 0 : nsIFrame* frame = GetPrimaryFrame(FlushType::None);
713 0 : if (frame) {
714 0 : *aStyledFrame = nsLayoutUtils::GetStyleFrame(frame);
715 : } else {
716 0 : *aStyledFrame = nullptr;
717 : }
718 : }
719 :
720 0 : if (isScrollingElement) {
721 : // Our scroll info should map to the root scrollable frame if there is one.
722 0 : if (nsIPresShell* shell = doc->GetShell()) {
723 0 : return shell->GetRootScrollFrameAsScrollable();
724 : }
725 : }
726 :
727 0 : return nullptr;
728 : }
729 :
730 : void
731 0 : Element::ScrollIntoView()
732 : {
733 0 : ScrollIntoView(ScrollIntoViewOptions());
734 0 : }
735 :
736 : void
737 0 : Element::ScrollIntoView(bool aTop)
738 : {
739 0 : ScrollIntoViewOptions options;
740 0 : if (!aTop) {
741 0 : options.mBlock = ScrollLogicalPosition::End;
742 : }
743 0 : ScrollIntoView(options);
744 0 : }
745 :
746 : void
747 0 : Element::ScrollIntoView(const ScrollIntoViewOptions &aOptions)
748 : {
749 0 : nsIDocument *document = GetComposedDoc();
750 0 : if (!document) {
751 0 : return;
752 : }
753 :
754 : // Get the presentation shell
755 0 : nsCOMPtr<nsIPresShell> presShell = document->GetShell();
756 0 : if (!presShell) {
757 0 : return;
758 : }
759 :
760 0 : int16_t vpercent = (aOptions.mBlock == ScrollLogicalPosition::Start)
761 : ? nsIPresShell::SCROLL_TOP
762 0 : : nsIPresShell::SCROLL_BOTTOM;
763 :
764 0 : uint32_t flags = nsIPresShell::SCROLL_OVERFLOW_HIDDEN;
765 0 : if (aOptions.mBehavior == ScrollBehavior::Smooth) {
766 0 : flags |= nsIPresShell::SCROLL_SMOOTH;
767 0 : } else if (aOptions.mBehavior == ScrollBehavior::Auto) {
768 0 : flags |= nsIPresShell::SCROLL_SMOOTH_AUTO;
769 : }
770 :
771 0 : presShell->ScrollContentIntoView(this,
772 : nsIPresShell::ScrollAxis(
773 : vpercent,
774 : nsIPresShell::SCROLL_ALWAYS),
775 : nsIPresShell::ScrollAxis(),
776 0 : flags);
777 : }
778 :
779 : void
780 0 : Element::Scroll(const CSSIntPoint& aScroll, const ScrollOptions& aOptions)
781 : {
782 0 : nsIScrollableFrame* sf = GetScrollFrame();
783 0 : if (sf) {
784 0 : nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT;
785 0 : if (aOptions.mBehavior == ScrollBehavior::Smooth) {
786 0 : scrollMode = nsIScrollableFrame::SMOOTH_MSD;
787 0 : } else if (aOptions.mBehavior == ScrollBehavior::Auto) {
788 0 : ScrollbarStyles styles = sf->GetScrollbarStyles();
789 0 : if (styles.mScrollBehavior == NS_STYLE_SCROLL_BEHAVIOR_SMOOTH) {
790 0 : scrollMode = nsIScrollableFrame::SMOOTH_MSD;
791 : }
792 : }
793 :
794 0 : sf->ScrollToCSSPixels(aScroll, scrollMode);
795 : }
796 0 : }
797 :
798 : void
799 0 : Element::Scroll(double aXScroll, double aYScroll)
800 : {
801 : // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
802 0 : auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),
803 0 : mozilla::ToZeroIfNonfinite(aYScroll));
804 :
805 0 : Scroll(scrollPos, ScrollOptions());
806 0 : }
807 :
808 : void
809 0 : Element::Scroll(const ScrollToOptions& aOptions)
810 : {
811 0 : nsIScrollableFrame *sf = GetScrollFrame();
812 0 : if (sf) {
813 0 : CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
814 0 : if (aOptions.mLeft.WasPassed()) {
815 0 : scrollPos.x = mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
816 : }
817 0 : if (aOptions.mTop.WasPassed()) {
818 0 : scrollPos.y = mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
819 : }
820 0 : Scroll(scrollPos, aOptions);
821 : }
822 0 : }
823 :
824 : void
825 0 : Element::ScrollTo(double aXScroll, double aYScroll)
826 : {
827 0 : Scroll(aXScroll, aYScroll);
828 0 : }
829 :
830 : void
831 0 : Element::ScrollTo(const ScrollToOptions& aOptions)
832 : {
833 0 : Scroll(aOptions);
834 0 : }
835 :
836 : void
837 0 : Element::ScrollBy(double aXScrollDif, double aYScrollDif)
838 : {
839 0 : nsIScrollableFrame *sf = GetScrollFrame();
840 0 : if (sf) {
841 0 : CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
842 0 : scrollPos += CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScrollDif),
843 0 : mozilla::ToZeroIfNonfinite(aYScrollDif));
844 0 : Scroll(scrollPos, ScrollOptions());
845 : }
846 0 : }
847 :
848 : void
849 0 : Element::ScrollBy(const ScrollToOptions& aOptions)
850 : {
851 0 : nsIScrollableFrame *sf = GetScrollFrame();
852 0 : if (sf) {
853 0 : CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
854 0 : if (aOptions.mLeft.WasPassed()) {
855 0 : scrollPos.x += mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
856 : }
857 0 : if (aOptions.mTop.WasPassed()) {
858 0 : scrollPos.y += mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
859 : }
860 0 : Scroll(scrollPos, aOptions);
861 : }
862 0 : }
863 :
864 : int32_t
865 0 : Element::ScrollTop()
866 : {
867 0 : nsIScrollableFrame* sf = GetScrollFrame();
868 0 : return sf ? sf->GetScrollPositionCSSPixels().y : 0;
869 : }
870 :
871 : void
872 0 : Element::SetScrollTop(int32_t aScrollTop)
873 : {
874 : // When aScrollTop is 0, we don't need to flush layout to scroll to that
875 : // point; we know 0 is always in range. At least we think so... But we do
876 : // need to flush frames so we ensure we find the right scrollable frame if
877 : // there is one.
878 : //
879 : // If aScrollTop is nonzero, we need to flush layout because we need to figure
880 : // out what our real scrollTopMax is.
881 0 : FlushType flushType = aScrollTop == 0 ? FlushType::Frames : FlushType::Layout;
882 0 : nsIScrollableFrame* sf = GetScrollFrame(nullptr, flushType);
883 0 : if (sf) {
884 0 : nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT;
885 0 : if (sf->GetScrollbarStyles().mScrollBehavior == NS_STYLE_SCROLL_BEHAVIOR_SMOOTH) {
886 0 : scrollMode = nsIScrollableFrame::SMOOTH_MSD;
887 : }
888 0 : sf->ScrollToCSSPixels(CSSIntPoint(sf->GetScrollPositionCSSPixels().x,
889 : aScrollTop),
890 0 : scrollMode);
891 : }
892 0 : }
893 :
894 : int32_t
895 0 : Element::ScrollLeft()
896 : {
897 0 : nsIScrollableFrame* sf = GetScrollFrame();
898 0 : return sf ? sf->GetScrollPositionCSSPixels().x : 0;
899 : }
900 :
901 : void
902 0 : Element::SetScrollLeft(int32_t aScrollLeft)
903 : {
904 : // We can't assume things here based on the value of aScrollLeft, because
905 : // depending on our direction and layout 0 may or may not be in our scroll
906 : // range. So we need to flush layout no matter what.
907 0 : nsIScrollableFrame* sf = GetScrollFrame();
908 0 : if (sf) {
909 0 : nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT;
910 0 : if (sf->GetScrollbarStyles().mScrollBehavior == NS_STYLE_SCROLL_BEHAVIOR_SMOOTH) {
911 0 : scrollMode = nsIScrollableFrame::SMOOTH_MSD;
912 : }
913 :
914 0 : sf->ScrollToCSSPixels(CSSIntPoint(aScrollLeft,
915 0 : sf->GetScrollPositionCSSPixels().y),
916 0 : scrollMode);
917 : }
918 0 : }
919 :
920 :
921 : bool
922 0 : Element::ScrollByNoFlush(int32_t aDx, int32_t aDy)
923 : {
924 0 : nsIScrollableFrame* sf = GetScrollFrame(nullptr, FlushType::None);
925 0 : if (!sf) {
926 0 : return false;
927 : }
928 :
929 0 : AutoWeakFrame weakRef(sf->GetScrolledFrame());
930 :
931 0 : CSSIntPoint before = sf->GetScrollPositionCSSPixels();
932 0 : sf->ScrollToCSSPixelsApproximate(CSSIntPoint(before.x + aDx, before.y + aDy));
933 :
934 : // The frame was destroyed, can't keep on scrolling.
935 0 : if (!weakRef.IsAlive()) {
936 0 : return false;
937 : }
938 :
939 0 : CSSIntPoint after = sf->GetScrollPositionCSSPixels();
940 0 : return (before != after);
941 : }
942 :
943 : void
944 0 : Element::MozScrollSnap()
945 : {
946 0 : nsIScrollableFrame* sf = GetScrollFrame(nullptr, FlushType::None);
947 0 : if (sf) {
948 0 : sf->ScrollSnap();
949 : }
950 0 : }
951 :
952 0 : static nsSize GetScrollRectSizeForOverflowVisibleFrame(nsIFrame* aFrame)
953 : {
954 0 : if (!aFrame) {
955 0 : return nsSize(0,0);
956 : }
957 :
958 0 : nsRect paddingRect = aFrame->GetPaddingRectRelativeToSelf();
959 0 : nsOverflowAreas overflowAreas(paddingRect, paddingRect);
960 : // Add the scrollable overflow areas of children (if any) to the paddingRect.
961 : // It's important to start with the paddingRect, otherwise if there are no
962 : // children the overflow rect will be 0,0,0,0 which will force the point 0,0
963 : // to be included in the final rect.
964 0 : nsLayoutUtils::UnionChildOverflow(aFrame, overflowAreas);
965 : // Make sure that an empty padding-rect's edges are included, by adding
966 : // the padding-rect in again with UnionEdges.
967 : nsRect overflowRect =
968 0 : overflowAreas.ScrollableOverflow().UnionEdges(paddingRect);
969 0 : return nsLayoutUtils::GetScrolledRect(aFrame,
970 0 : overflowRect, paddingRect.Size(),
971 0 : aFrame->StyleVisibility()->mDirection).Size();
972 : }
973 :
974 : int32_t
975 0 : Element::ScrollHeight()
976 : {
977 0 : if (IsSVGElement())
978 0 : return 0;
979 :
980 0 : nsIScrollableFrame* sf = GetScrollFrame();
981 : nscoord height;
982 0 : if (sf) {
983 0 : height = sf->GetScrollRange().height + sf->GetScrollPortRect().height;
984 : } else {
985 0 : height = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).height;
986 : }
987 :
988 0 : return nsPresContext::AppUnitsToIntCSSPixels(height);
989 : }
990 :
991 : int32_t
992 0 : Element::ScrollWidth()
993 : {
994 0 : if (IsSVGElement())
995 0 : return 0;
996 :
997 0 : nsIScrollableFrame* sf = GetScrollFrame();
998 : nscoord width;
999 0 : if (sf) {
1000 0 : width = sf->GetScrollRange().width + sf->GetScrollPortRect().width;
1001 : } else {
1002 0 : width = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).width;
1003 : }
1004 :
1005 0 : return nsPresContext::AppUnitsToIntCSSPixels(width);
1006 : }
1007 :
1008 : nsRect
1009 0 : Element::GetClientAreaRect()
1010 : {
1011 : nsIFrame* styledFrame;
1012 0 : nsIScrollableFrame* sf = GetScrollFrame(&styledFrame);
1013 :
1014 0 : if (sf) {
1015 0 : return sf->GetScrollPortRect();
1016 : }
1017 :
1018 0 : if (styledFrame &&
1019 0 : (styledFrame->StyleDisplay()->mDisplay != StyleDisplay::Inline ||
1020 0 : styledFrame->IsFrameOfType(nsIFrame::eReplaced))) {
1021 : // Special case code to make client area work even when there isn't
1022 : // a scroll view, see bug 180552, bug 227567.
1023 0 : return styledFrame->GetPaddingRect() - styledFrame->GetPositionIgnoringScrolling();
1024 : }
1025 :
1026 : // SVG nodes reach here and just return 0
1027 0 : return nsRect(0, 0, 0, 0);
1028 : }
1029 :
1030 : already_AddRefed<DOMRect>
1031 2 : Element::GetBoundingClientRect()
1032 : {
1033 4 : RefPtr<DOMRect> rect = new DOMRect(this);
1034 :
1035 2 : nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
1036 2 : if (!frame) {
1037 : // display:none, perhaps? Return the empty rect
1038 0 : return rect.forget();
1039 : }
1040 :
1041 : nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame,
1042 : nsLayoutUtils::GetContainingBlockForClientRect(frame),
1043 4 : nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
1044 2 : rect->SetLayoutRect(r);
1045 2 : return rect.forget();
1046 : }
1047 :
1048 : already_AddRefed<DOMRectList>
1049 0 : Element::GetClientRects()
1050 : {
1051 0 : RefPtr<DOMRectList> rectList = new DOMRectList(this);
1052 :
1053 0 : nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
1054 0 : if (!frame) {
1055 : // display:none, perhaps? Return an empty list
1056 0 : return rectList.forget();
1057 : }
1058 :
1059 0 : nsLayoutUtils::RectListBuilder builder(rectList);
1060 0 : nsLayoutUtils::GetAllInFlowRects(frame,
1061 : nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder,
1062 0 : nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
1063 0 : return rectList.forget();
1064 : }
1065 :
1066 : //----------------------------------------------------------------------
1067 :
1068 : void
1069 1343 : Element::AddToIdTable(nsIAtom* aId)
1070 : {
1071 1343 : NS_ASSERTION(HasID(), "Node doesn't have an ID?");
1072 1343 : if (IsInShadowTree()) {
1073 0 : ShadowRoot* containingShadow = GetContainingShadow();
1074 0 : containingShadow->AddToIdTable(this, aId);
1075 : } else {
1076 1343 : nsIDocument* doc = GetUncomposedDoc();
1077 1343 : if (doc && (!IsInAnonymousSubtree() || doc->IsXULDocument())) {
1078 1052 : doc->AddToIdTable(this, aId);
1079 : }
1080 : }
1081 1343 : }
1082 :
1083 : void
1084 1032 : Element::RemoveFromIdTable()
1085 : {
1086 1032 : if (!HasID()) {
1087 890 : return;
1088 : }
1089 :
1090 142 : nsIAtom* id = DoGetID();
1091 142 : if (IsInShadowTree()) {
1092 0 : ShadowRoot* containingShadow = GetContainingShadow();
1093 : // Check for containingShadow because it may have
1094 : // been deleted during unlinking.
1095 0 : if (containingShadow) {
1096 0 : containingShadow->RemoveFromIdTable(this, id);
1097 : }
1098 : } else {
1099 142 : nsIDocument* doc = GetUncomposedDoc();
1100 142 : if (doc && (!IsInAnonymousSubtree() || doc->IsXULDocument())) {
1101 28 : doc->RemoveFromIdTable(this, id);
1102 : }
1103 : }
1104 : }
1105 :
1106 : already_AddRefed<ShadowRoot>
1107 0 : Element::CreateShadowRoot(ErrorResult& aError)
1108 : {
1109 0 : nsAutoScriptBlocker scriptBlocker;
1110 :
1111 0 : RefPtr<mozilla::dom::NodeInfo> nodeInfo;
1112 0 : nodeInfo = mNodeInfo->NodeInfoManager()->GetNodeInfo(
1113 : nsGkAtoms::documentFragmentNodeName, nullptr, kNameSpaceID_None,
1114 0 : nsIDOMNode::DOCUMENT_FRAGMENT_NODE);
1115 :
1116 0 : RefPtr<nsXBLDocumentInfo> docInfo = new nsXBLDocumentInfo(OwnerDoc());
1117 :
1118 0 : nsXBLPrototypeBinding* protoBinding = new nsXBLPrototypeBinding();
1119 0 : aError = protoBinding->Init(NS_LITERAL_CSTRING("shadowroot"),
1120 0 : docInfo, nullptr, true);
1121 0 : if (aError.Failed()) {
1122 0 : delete protoBinding;
1123 0 : return nullptr;
1124 : }
1125 :
1126 0 : nsIDocument* doc = GetComposedDoc();
1127 0 : nsIContent* destroyedFramesFor = nullptr;
1128 0 : if (doc) {
1129 0 : nsIPresShell* shell = doc->GetShell();
1130 0 : if (shell) {
1131 0 : shell->DestroyFramesFor(this, &destroyedFramesFor);
1132 0 : MOZ_ASSERT(!shell->FrameManager()->GetDisplayContentsStyleFor(this));
1133 : }
1134 : }
1135 0 : MOZ_ASSERT(!GetPrimaryFrame());
1136 :
1137 : // Unlike for XBL, false is the default for inheriting style.
1138 0 : protoBinding->SetInheritsStyle(false);
1139 :
1140 : // Calling SetPrototypeBinding takes ownership of protoBinding.
1141 0 : docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
1142 :
1143 0 : RefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
1144 0 : protoBinding);
1145 :
1146 0 : shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
1147 :
1148 : // Replace the old ShadowRoot with the new one and let the old
1149 : // ShadowRoot know about the younger ShadowRoot because the old
1150 : // ShadowRoot is projected into the younger ShadowRoot's shadow
1151 : // insertion point (if it exists).
1152 0 : ShadowRoot* olderShadow = GetShadowRoot();
1153 0 : SetShadowRoot(shadowRoot);
1154 0 : if (olderShadow) {
1155 0 : olderShadow->SetYoungerShadow(shadowRoot);
1156 :
1157 : // Unbind children of older shadow root because they
1158 : // are no longer in the composed tree.
1159 0 : for (nsIContent* child = olderShadow->GetFirstChild(); child;
1160 0 : child = child->GetNextSibling()) {
1161 0 : child->UnbindFromTree(true, false);
1162 : }
1163 :
1164 0 : olderShadow->SetIsComposedDocParticipant(false);
1165 : }
1166 :
1167 : // xblBinding takes ownership of docInfo.
1168 0 : RefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);
1169 0 : shadowRoot->SetAssociatedBinding(xblBinding);
1170 0 : xblBinding->SetBoundElement(this);
1171 :
1172 0 : SetXBLBinding(xblBinding);
1173 :
1174 : // Recreate the frame for the bound content because binding a ShadowRoot
1175 : // changes how things are rendered.
1176 0 : if (doc) {
1177 0 : MOZ_ASSERT(doc == GetComposedDoc());
1178 0 : nsIPresShell* shell = doc->GetShell();
1179 0 : if (shell) {
1180 0 : shell->CreateFramesFor(destroyedFramesFor);
1181 : }
1182 : }
1183 :
1184 0 : return shadowRoot.forget();
1185 : }
1186 :
1187 0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DestinationInsertionPointList, mParent,
1188 : mDestinationPoints)
1189 :
1190 0 : NS_INTERFACE_TABLE_HEAD(DestinationInsertionPointList)
1191 0 : NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
1192 0 : NS_INTERFACE_TABLE(DestinationInsertionPointList, nsINodeList, nsIDOMNodeList)
1193 0 : NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DestinationInsertionPointList)
1194 0 : NS_INTERFACE_MAP_END
1195 :
1196 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(DestinationInsertionPointList)
1197 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(DestinationInsertionPointList)
1198 :
1199 0 : DestinationInsertionPointList::DestinationInsertionPointList(Element* aElement)
1200 0 : : mParent(aElement)
1201 : {
1202 0 : nsTArray<nsIContent*>* destPoints = aElement->GetExistingDestInsertionPoints();
1203 0 : if (destPoints) {
1204 0 : for (uint32_t i = 0; i < destPoints->Length(); i++) {
1205 0 : mDestinationPoints.AppendElement(destPoints->ElementAt(i));
1206 : }
1207 : }
1208 0 : }
1209 :
1210 0 : DestinationInsertionPointList::~DestinationInsertionPointList()
1211 : {
1212 0 : }
1213 :
1214 : nsIContent*
1215 0 : DestinationInsertionPointList::Item(uint32_t aIndex)
1216 : {
1217 0 : return mDestinationPoints.SafeElementAt(aIndex);
1218 : }
1219 :
1220 : NS_IMETHODIMP
1221 0 : DestinationInsertionPointList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
1222 : {
1223 0 : nsIContent* item = Item(aIndex);
1224 0 : if (!item) {
1225 0 : return NS_ERROR_FAILURE;
1226 : }
1227 :
1228 0 : return CallQueryInterface(item, aReturn);
1229 : }
1230 :
1231 : uint32_t
1232 0 : DestinationInsertionPointList::Length() const
1233 : {
1234 0 : return mDestinationPoints.Length();
1235 : }
1236 :
1237 : NS_IMETHODIMP
1238 0 : DestinationInsertionPointList::GetLength(uint32_t* aLength)
1239 : {
1240 0 : *aLength = Length();
1241 0 : return NS_OK;
1242 : }
1243 :
1244 : int32_t
1245 0 : DestinationInsertionPointList::IndexOf(nsIContent* aContent)
1246 : {
1247 0 : return mDestinationPoints.IndexOf(aContent);
1248 : }
1249 :
1250 : JSObject*
1251 0 : DestinationInsertionPointList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
1252 : {
1253 0 : return NodeListBinding::Wrap(aCx, this, aGivenProto);
1254 : }
1255 :
1256 : already_AddRefed<DestinationInsertionPointList>
1257 0 : Element::GetDestinationInsertionPoints()
1258 : {
1259 : RefPtr<DestinationInsertionPointList> list =
1260 0 : new DestinationInsertionPointList(this);
1261 0 : return list.forget();
1262 : }
1263 :
1264 : void
1265 253 : Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
1266 : {
1267 : const nsAttrValue* val =
1268 260 : mAttrsAndChildren.GetAttr(aName,
1269 260 : IsHTMLElement() && IsInHTMLDocument() ?
1270 253 : eIgnoreCase : eCaseMatters);
1271 253 : if (val) {
1272 134 : val->ToString(aReturn);
1273 : } else {
1274 119 : if (IsXULElement()) {
1275 : // XXX should be SetDOMStringToNull(aReturn);
1276 : // See bug 232598
1277 : // aReturn is already empty
1278 : } else {
1279 7 : aReturn.SetNull();
1280 : }
1281 : }
1282 253 : }
1283 :
1284 : void
1285 366 : Element::SetAttribute(const nsAString& aName,
1286 : const nsAString& aValue,
1287 : ErrorResult& aError)
1288 : {
1289 366 : aError = nsContentUtils::CheckQName(aName, false);
1290 366 : if (aError.Failed()) {
1291 0 : return;
1292 : }
1293 :
1294 732 : nsAutoString nameToUse;
1295 366 : const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
1296 366 : if (!name) {
1297 556 : nsCOMPtr<nsIAtom> nameAtom = NS_AtomizeMainThread(nameToUse);
1298 278 : if (!nameAtom) {
1299 0 : aError.Throw(NS_ERROR_OUT_OF_MEMORY);
1300 0 : return;
1301 : }
1302 278 : aError = SetAttr(kNameSpaceID_None, nameAtom, aValue, true);
1303 278 : return;
1304 : }
1305 :
1306 88 : aError = SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
1307 176 : aValue, true);
1308 88 : return;
1309 : }
1310 :
1311 : void
1312 101 : Element::RemoveAttribute(const nsAString& aName, ErrorResult& aError)
1313 : {
1314 101 : const nsAttrName* name = InternalGetAttrNameFromQName(aName);
1315 :
1316 101 : if (!name) {
1317 : // If there is no canonical nsAttrName for this attribute name, then the
1318 : // attribute does not exist and we can't get its namespace ID and
1319 : // local name below, so we return early.
1320 85 : return;
1321 : }
1322 :
1323 : // Hold a strong reference here so that the atom or nodeinfo doesn't go
1324 : // away during UnsetAttr. If it did UnsetAttr would be left with a
1325 : // dangling pointer as argument without knowing it.
1326 32 : nsAttrName tmp(*name);
1327 :
1328 16 : aError = UnsetAttr(name->NamespaceID(), name->LocalName(), true);
1329 : }
1330 :
1331 : Attr*
1332 0 : Element::GetAttributeNode(const nsAString& aName)
1333 : {
1334 0 : OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNode);
1335 0 : return Attributes()->GetNamedItem(aName);
1336 : }
1337 :
1338 : already_AddRefed<Attr>
1339 0 : Element::SetAttributeNode(Attr& aNewAttr, ErrorResult& aError)
1340 : {
1341 : // XXXbz can we just remove this warning and the one in setAttributeNodeNS and
1342 : // alias setAttributeNode to setAttributeNodeNS?
1343 0 : OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNode);
1344 :
1345 0 : return Attributes()->SetNamedItemNS(aNewAttr, aError);
1346 : }
1347 :
1348 : already_AddRefed<Attr>
1349 0 : Element::RemoveAttributeNode(Attr& aAttribute,
1350 : ErrorResult& aError)
1351 : {
1352 0 : Element *elem = aAttribute.GetElement();
1353 0 : if (elem != this) {
1354 0 : aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
1355 0 : return nullptr;
1356 : }
1357 :
1358 0 : OwnerDoc()->WarnOnceAbout(nsIDocument::eRemoveAttributeNode);
1359 0 : nsAutoString nameSpaceURI;
1360 0 : aAttribute.NodeInfo()->GetNamespaceURI(nameSpaceURI);
1361 0 : return Attributes()->RemoveNamedItemNS(nameSpaceURI, aAttribute.NodeInfo()->LocalName(), aError);
1362 : }
1363 :
1364 : void
1365 0 : Element::GetAttributeNS(const nsAString& aNamespaceURI,
1366 : const nsAString& aLocalName,
1367 : nsAString& aReturn)
1368 : {
1369 : int32_t nsid =
1370 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI,
1371 0 : nsContentUtils::IsChromeDoc(OwnerDoc()));
1372 :
1373 0 : if (nsid == kNameSpaceID_Unknown) {
1374 : // Unknown namespace means no attribute.
1375 0 : SetDOMStringToNull(aReturn);
1376 0 : return;
1377 : }
1378 :
1379 0 : nsCOMPtr<nsIAtom> name = NS_AtomizeMainThread(aLocalName);
1380 0 : bool hasAttr = GetAttr(nsid, name, aReturn);
1381 0 : if (!hasAttr) {
1382 0 : SetDOMStringToNull(aReturn);
1383 : }
1384 : }
1385 :
1386 : void
1387 0 : Element::SetAttributeNS(const nsAString& aNamespaceURI,
1388 : const nsAString& aQualifiedName,
1389 : const nsAString& aValue,
1390 : ErrorResult& aError)
1391 : {
1392 0 : RefPtr<mozilla::dom::NodeInfo> ni;
1393 0 : aError =
1394 : nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, aQualifiedName,
1395 : mNodeInfo->NodeInfoManager(),
1396 : nsIDOMNode::ATTRIBUTE_NODE,
1397 0 : getter_AddRefs(ni));
1398 0 : if (aError.Failed()) {
1399 0 : return;
1400 : }
1401 :
1402 0 : aError = SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(),
1403 0 : aValue, true);
1404 : }
1405 :
1406 : void
1407 0 : Element::RemoveAttributeNS(const nsAString& aNamespaceURI,
1408 : const nsAString& aLocalName,
1409 : ErrorResult& aError)
1410 : {
1411 0 : nsCOMPtr<nsIAtom> name = NS_AtomizeMainThread(aLocalName);
1412 : int32_t nsid =
1413 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI,
1414 0 : nsContentUtils::IsChromeDoc(OwnerDoc()));
1415 :
1416 0 : if (nsid == kNameSpaceID_Unknown) {
1417 : // If the namespace ID is unknown, it means there can't possibly be an
1418 : // existing attribute. We would need a known namespace ID to pass into
1419 : // UnsetAttr, so we return early if we don't have one.
1420 0 : return;
1421 : }
1422 :
1423 0 : aError = UnsetAttr(nsid, name, true);
1424 : }
1425 :
1426 : Attr*
1427 0 : Element::GetAttributeNodeNS(const nsAString& aNamespaceURI,
1428 : const nsAString& aLocalName)
1429 : {
1430 0 : OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNodeNS);
1431 :
1432 0 : return GetAttributeNodeNSInternal(aNamespaceURI, aLocalName);
1433 : }
1434 :
1435 : Attr*
1436 0 : Element::GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
1437 : const nsAString& aLocalName)
1438 : {
1439 0 : return Attributes()->GetNamedItemNS(aNamespaceURI, aLocalName);
1440 : }
1441 :
1442 : already_AddRefed<Attr>
1443 0 : Element::SetAttributeNodeNS(Attr& aNewAttr,
1444 : ErrorResult& aError)
1445 : {
1446 0 : OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNodeNS);
1447 0 : return Attributes()->SetNamedItemNS(aNewAttr, aError);
1448 : }
1449 :
1450 : already_AddRefed<nsIHTMLCollection>
1451 1 : Element::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
1452 : const nsAString& aLocalName,
1453 : ErrorResult& aError)
1454 : {
1455 1 : int32_t nameSpaceId = kNameSpaceID_Wildcard;
1456 :
1457 1 : if (!aNamespaceURI.EqualsLiteral("*")) {
1458 1 : aError =
1459 : nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
1460 1 : nameSpaceId);
1461 1 : if (aError.Failed()) {
1462 0 : return nullptr;
1463 : }
1464 : }
1465 :
1466 1 : NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
1467 :
1468 1 : return NS_GetContentList(this, nameSpaceId, aLocalName);
1469 : }
1470 :
1471 : bool
1472 0 : Element::HasAttributeNS(const nsAString& aNamespaceURI,
1473 : const nsAString& aLocalName) const
1474 : {
1475 : int32_t nsid =
1476 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI,
1477 0 : nsContentUtils::IsChromeDoc(OwnerDoc()));
1478 :
1479 0 : if (nsid == kNameSpaceID_Unknown) {
1480 : // Unknown namespace means no attr...
1481 0 : return false;
1482 : }
1483 :
1484 0 : nsCOMPtr<nsIAtom> name = NS_AtomizeMainThread(aLocalName);
1485 0 : return HasAttr(nsid, name);
1486 : }
1487 :
1488 : already_AddRefed<nsIHTMLCollection>
1489 0 : Element::GetElementsByClassName(const nsAString& aClassNames)
1490 : {
1491 0 : return nsContentUtils::GetElementsByClassName(this, aClassNames);
1492 : }
1493 :
1494 : /**
1495 : * Returns the count of descendants (inclusive of aContent) in
1496 : * the uncomposed document that are explicitly set as editable.
1497 : */
1498 : static uint32_t
1499 3649 : EditableInclusiveDescendantCount(nsIContent* aContent)
1500 : {
1501 3649 : auto htmlElem = nsGenericHTMLElement::FromContent(aContent);
1502 3649 : if (htmlElem) {
1503 121 : return htmlElem->EditableInclusiveDescendantCount();
1504 : }
1505 :
1506 3528 : return aContent->EditableDescendantCount();
1507 : }
1508 :
1509 : nsresult
1510 4764 : Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
1511 : nsIContent* aBindingParent,
1512 : bool aCompileEventHandlers)
1513 : {
1514 4764 : NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
1515 4764 : NS_PRECONDITION((NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc()),
1516 : "Must have the same owner document");
1517 4764 : NS_PRECONDITION(!aParent || aDocument == aParent->GetUncomposedDoc(),
1518 : "aDocument must be current doc of aParent");
1519 4764 : NS_PRECONDITION(!GetUncomposedDoc(), "Already have a document. Unbind first!");
1520 : // Note that as we recurse into the kids, they'll have a non-null parent. So
1521 : // only assert if our parent is _changing_ while we have a parent.
1522 4764 : NS_PRECONDITION(!GetParent() || aParent == GetParent(),
1523 : "Already have a parent. Unbind first!");
1524 4764 : NS_PRECONDITION(!GetBindingParent() ||
1525 : aBindingParent == GetBindingParent() ||
1526 : (!aBindingParent && aParent &&
1527 : aParent->GetBindingParent() == GetBindingParent()),
1528 : "Already have a binding parent. Unbind first!");
1529 4764 : NS_PRECONDITION(!aParent || !aDocument ||
1530 : !aParent->HasFlag(NODE_FORCE_XBL_BINDINGS),
1531 : "Parent in document but flagged as forcing XBL");
1532 4764 : NS_PRECONDITION(aBindingParent != this,
1533 : "Content must not be its own binding parent");
1534 4764 : NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
1535 : aBindingParent == aParent,
1536 : "Native anonymous content must have its parent as its "
1537 : "own binding parent");
1538 4764 : NS_PRECONDITION(aBindingParent || !aParent ||
1539 : aBindingParent == aParent->GetBindingParent(),
1540 : "We should be passed the right binding parent");
1541 :
1542 : #ifdef MOZ_XUL
1543 : // First set the binding parent
1544 4764 : nsXULElement* xulElem = nsXULElement::FromContent(this);
1545 4764 : if (xulElem) {
1546 3702 : xulElem->SetXULBindingParent(aBindingParent);
1547 : }
1548 : else
1549 : #endif
1550 : {
1551 1062 : if (aBindingParent) {
1552 231 : nsDOMSlots *slots = DOMSlots();
1553 :
1554 231 : slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
1555 : }
1556 : }
1557 4764 : NS_ASSERTION(!aBindingParent || IsRootOfNativeAnonymousSubtree() ||
1558 : !HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) ||
1559 : (aParent && aParent->IsInNativeAnonymousSubtree()),
1560 : "Trying to re-bind content from native anonymous subtree to "
1561 : "non-native anonymous parent!");
1562 4764 : if (aParent) {
1563 4709 : if (aParent->IsInNativeAnonymousSubtree()) {
1564 28 : SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
1565 : }
1566 4709 : if (aParent->HasFlag(NODE_CHROME_ONLY_ACCESS)) {
1567 0 : SetFlags(NODE_CHROME_ONLY_ACCESS);
1568 : }
1569 4709 : if (HasFlag(NODE_IS_ANONYMOUS_ROOT)) {
1570 416 : aParent->SetMayHaveAnonymousChildren();
1571 : }
1572 4709 : if (aParent->IsInShadowTree()) {
1573 0 : ClearSubtreeRootPointer();
1574 0 : SetFlags(NODE_IS_IN_SHADOW_TREE);
1575 : }
1576 4709 : ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
1577 4709 : if (parentContainingShadow) {
1578 0 : DOMSlots()->mContainingShadow = parentContainingShadow;
1579 : }
1580 : }
1581 :
1582 4764 : bool hadForceXBL = HasFlag(NODE_FORCE_XBL_BINDINGS);
1583 :
1584 4764 : bool hadParent = !!GetParentNode();
1585 :
1586 : // Now set the parent and set the "Force attach xbl" flag if needed.
1587 4764 : if (aParent) {
1588 4709 : if (!GetParent()) {
1589 3377 : NS_ADDREF(aParent);
1590 : }
1591 4709 : mParent = aParent;
1592 :
1593 4709 : if (aParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
1594 4 : SetFlags(NODE_FORCE_XBL_BINDINGS);
1595 : }
1596 : }
1597 : else {
1598 55 : mParent = aDocument;
1599 : }
1600 4764 : SetParentIsContent(aParent);
1601 :
1602 : // XXXbz sXBL/XBL2 issue!
1603 :
1604 : // Finally, set the document
1605 4764 : if (aDocument) {
1606 : // Notify XBL- & nsIAnonymousContentCreator-generated
1607 : // anonymous content that the document is changing.
1608 : // XXXbz ordering issues here? Probably not, since ChangeDocumentFor is
1609 : // just pretty broken anyway.... Need to get it working.
1610 : // XXXbz XBL doesn't handle this (asserts), and we don't really want
1611 : // to be doing this during parsing anyway... sort this out.
1612 : // aDocument->BindingManager()->ChangeDocumentFor(this, nullptr,
1613 : // aDocument);
1614 :
1615 : // We no longer need to track the subtree pointer (and in fact we'll assert
1616 : // if we do this any later).
1617 2995 : ClearSubtreeRootPointer();
1618 :
1619 : // Being added to a document.
1620 2995 : SetIsInDocument();
1621 :
1622 : // Unset this flag since we now really are in a document.
1623 2995 : UnsetFlags(NODE_FORCE_XBL_BINDINGS |
1624 : // And clear the lazy frame construction bits.
1625 2995 : NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
1626 : // And the restyle bits
1627 2995 : UnsetRestyleFlagsIfGecko();
1628 1769 : } else if (IsInShadowTree()) {
1629 : // We're not in a document, but we did get inserted into a shadow tree.
1630 : // Since we won't have any restyle data in the document's restyle trackers,
1631 : // don't let us get inserted with restyle bits set incorrectly.
1632 : //
1633 : // Also clear all the other flags that are cleared above when we do get
1634 : // inserted into a document.
1635 0 : UnsetFlags(NODE_FORCE_XBL_BINDINGS |
1636 0 : NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
1637 0 : UnsetRestyleFlagsIfGecko();
1638 : } else {
1639 : // If we're not in the doc and not in a shadow tree,
1640 : // update our subtree pointer.
1641 1769 : SetSubtreeRootPointer(aParent->SubtreeRoot());
1642 : }
1643 :
1644 4764 : nsIDocument* composedDoc = GetComposedDoc();
1645 4764 : if (composedDoc) {
1646 : // Attached callback must be enqueued whenever custom element is inserted into a
1647 : // document and this document has a browsing context.
1648 2995 : if (GetCustomElementData() && composedDoc->GetDocShell()) {
1649 : // Enqueue an attached callback for the custom element.
1650 : nsContentUtils::EnqueueLifecycleCallback(
1651 0 : composedDoc, nsIDocument::eAttached, this);
1652 : }
1653 : }
1654 :
1655 : // Propagate scoped style sheet tracking bit.
1656 4764 : if (mParent->IsContent()) {
1657 : nsIContent* parent;
1658 4709 : ShadowRoot* shadowRootParent = ShadowRoot::FromNode(mParent);
1659 4709 : if (shadowRootParent) {
1660 0 : parent = shadowRootParent->GetHost();
1661 : } else {
1662 4709 : parent = mParent->AsContent();
1663 : }
1664 :
1665 4709 : bool inStyleScope = parent->IsElementInStyleScope();
1666 :
1667 4709 : SetIsElementInStyleScope(inStyleScope);
1668 4709 : SetIsElementInStyleScopeFlagOnShadowTree(inStyleScope);
1669 : }
1670 :
1671 : // This has to be here, rather than in nsGenericHTMLElement::BindToTree,
1672 : // because it has to happen after updating the parent pointer, but before
1673 : // recursively binding the kids.
1674 4764 : if (IsHTMLElement()) {
1675 130 : SetDirOnBind(this, aParent);
1676 : }
1677 :
1678 4764 : uint32_t editableDescendantCount = 0;
1679 :
1680 : // If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
1681 : // that also need to be told that they are moving.
1682 : nsresult rv;
1683 4764 : if (hadForceXBL) {
1684 6 : nsBindingManager* bmgr = OwnerDoc()->BindingManager();
1685 :
1686 6 : nsXBLBinding* contBinding = bmgr->GetBindingWithContent(this);
1687 : // First check if we have a binding...
1688 6 : if (contBinding) {
1689 4 : nsCOMPtr<nsIContent> anonRoot = contBinding->GetAnonymousContent();
1690 2 : bool allowScripts = contBinding->AllowScripts();
1691 4 : for (nsCOMPtr<nsIContent> child = anonRoot->GetFirstChild();
1692 : child;
1693 2 : child = child->GetNextSibling()) {
1694 2 : rv = child->BindToTree(aDocument, this, this, allowScripts);
1695 2 : NS_ENSURE_SUCCESS(rv, rv);
1696 :
1697 2 : editableDescendantCount += EditableInclusiveDescendantCount(child);
1698 : }
1699 : }
1700 : }
1701 :
1702 4764 : UpdateEditableState(false);
1703 :
1704 : // Now recurse into our kids
1705 6260 : for (nsIContent* child = GetFirstChild(); child;
1706 1496 : child = child->GetNextSibling()) {
1707 1496 : rv = child->BindToTree(aDocument, this, aBindingParent,
1708 2992 : aCompileEventHandlers);
1709 1496 : NS_ENSURE_SUCCESS(rv, rv);
1710 :
1711 1496 : editableDescendantCount += EditableInclusiveDescendantCount(child);
1712 : }
1713 :
1714 4764 : if (aDocument) {
1715 : // Update our editable descendant count because we don't keep track of it
1716 : // for content that is not in the uncomposed document.
1717 2995 : MOZ_ASSERT(EditableDescendantCount() == 0);
1718 2995 : ChangeEditableDescendantCount(editableDescendantCount);
1719 :
1720 2995 : if (!hadParent) {
1721 2116 : uint32_t editableDescendantChange = EditableInclusiveDescendantCount(this);
1722 2116 : if (editableDescendantChange != 0) {
1723 : // If we are binding a subtree root to the document, we need to update
1724 : // the editable descendant count of all the ancestors.
1725 0 : nsIContent* parent = GetParent();
1726 0 : while (parent) {
1727 0 : parent->ChangeEditableDescendantCount(editableDescendantChange);
1728 0 : parent = parent->GetParent();
1729 : }
1730 : }
1731 : }
1732 : }
1733 :
1734 4764 : nsNodeUtils::ParentChainChanged(this);
1735 4764 : if (!hadParent && IsRootOfNativeAnonymousSubtree()) {
1736 45 : nsNodeUtils::NativeAnonymousChildListChange(this, false);
1737 : }
1738 :
1739 4764 : if (HasID()) {
1740 1227 : AddToIdTable(DoGetID());
1741 : }
1742 :
1743 4764 : if (MayHaveStyle() && !IsXULElement()) {
1744 : // XXXbz if we already have a style attr parsed, this won't do
1745 : // anything... need to fix that.
1746 : // If MayHaveStyle() is true, we must be an nsStyledElement
1747 0 : static_cast<nsStyledElement*>(this)->ReparseStyleAttribute(false, false);
1748 : }
1749 :
1750 : // Call BindToTree on shadow root children.
1751 4764 : ShadowRoot* shadowRoot = GetShadowRoot();
1752 4764 : if (shadowRoot) {
1753 0 : shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
1754 0 : for (nsIContent* child = shadowRoot->GetFirstChild(); child;
1755 0 : child = child->GetNextSibling()) {
1756 0 : rv = child->BindToTree(nullptr, shadowRoot,
1757 0 : shadowRoot->GetBindingParent(),
1758 0 : aCompileEventHandlers);
1759 0 : NS_ENSURE_SUCCESS(rv, rv);
1760 : }
1761 : }
1762 :
1763 : // Pseudo-elements implemented by JS must have the NODE_IS_NATIVE_ANONYMOUS
1764 : // flag set on them. For C++-created pseudo-elements, this is done in
1765 : // nsCSSFrameConstructor::GetAnonymousContent, but any JS that creates
1766 : // pseudo-elements would run after that. So we set that flag here,
1767 : // when the element implementing the pseudo is inserted into the document.
1768 : // We maintain the invariant that any NAC-implemented pseudo-element's
1769 : // anonymous ancestors are also flagged as NAC, which the style system relies on.
1770 4764 : if (aDocument) {
1771 2995 : CSSPseudoElementType pseudoType = GetPseudoElementType();
1772 3005 : if (pseudoType != CSSPseudoElementType::NotPseudo &&
1773 10 : nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType)) {
1774 0 : SetFlags(NODE_IS_NATIVE_ANONYMOUS);
1775 0 : nsIContent* parent = aParent;
1776 0 : while (parent && !parent->IsRootOfNativeAnonymousSubtree()) {
1777 0 : MOZ_ASSERT(parent->IsInNativeAnonymousSubtree());
1778 0 : parent->SetFlags(NODE_IS_NATIVE_ANONYMOUS);
1779 0 : parent = parent->GetParent();
1780 : }
1781 0 : MOZ_ASSERT(parent);
1782 : }
1783 : }
1784 :
1785 : // XXXbz script execution during binding can trigger some of these
1786 : // postcondition asserts.... But we do want that, since things will
1787 : // generally be quite broken when that happens.
1788 4764 : NS_POSTCONDITION(aDocument == GetUncomposedDoc(), "Bound to wrong document");
1789 4764 : NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
1790 4764 : NS_POSTCONDITION(aBindingParent == GetBindingParent(),
1791 : "Bound to wrong binding parent");
1792 :
1793 4764 : return NS_OK;
1794 : }
1795 :
1796 12 : RemoveFromBindingManagerRunnable::RemoveFromBindingManagerRunnable(
1797 : nsBindingManager* aManager,
1798 : nsIContent* aContent,
1799 12 : nsIDocument* aDoc)
1800 : : mozilla::Runnable("dom::RemoveFromBindingManagerRunnable")
1801 : , mManager(aManager)
1802 : , mContent(aContent)
1803 12 : , mDoc(aDoc)
1804 12 : {}
1805 :
1806 36 : RemoveFromBindingManagerRunnable::~RemoveFromBindingManagerRunnable() {}
1807 :
1808 : NS_IMETHODIMP
1809 12 : RemoveFromBindingManagerRunnable::Run()
1810 : {
1811 : // It may be the case that the element was removed from the
1812 : // DOM, causing this runnable to be created, then inserted back
1813 : // into the document before the this runnable had a chance to
1814 : // tear down the binding. Only tear down the binding if the element
1815 : // is still no longer in the DOM. nsXBLService::LoadBinding tears
1816 : // down the old binding if the element is inserted back into the
1817 : // DOM and loads a different binding.
1818 12 : if (!mContent->IsInComposedDoc()) {
1819 12 : mManager->RemovedFromDocumentInternal(mContent, mDoc,
1820 12 : nsBindingManager::eRunDtor);
1821 : }
1822 :
1823 12 : return NS_OK;
1824 : }
1825 :
1826 :
1827 : void
1828 912 : Element::UnbindFromTree(bool aDeep, bool aNullParent)
1829 : {
1830 912 : NS_PRECONDITION(aDeep || (!GetUncomposedDoc() && !GetBindingParent()),
1831 : "Shallow unbind won't clear document and binding parent on "
1832 : "kids!");
1833 :
1834 912 : RemoveFromIdTable();
1835 :
1836 : // Make sure to unbind this node before doing the kids
1837 : nsIDocument* document =
1838 912 : HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetComposedDoc();
1839 :
1840 912 : if (HasPointerLock()) {
1841 0 : nsIDocument::UnlockPointer();
1842 : }
1843 912 : if (mState.HasState(NS_EVENT_STATE_FULL_SCREEN)) {
1844 : // The element being removed is an ancestor of the full-screen element,
1845 : // exit full-screen state.
1846 0 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
1847 0 : NS_LITERAL_CSTRING("DOM"), OwnerDoc(),
1848 : nsContentUtils::eDOM_PROPERTIES,
1849 0 : "RemovedFullscreenElement");
1850 : // Fully exit full-screen.
1851 0 : nsIDocument::ExitFullscreenInDocTree(OwnerDoc());
1852 : }
1853 912 : if (aNullParent) {
1854 511 : if (GetParent() && GetParent()->IsInUncomposedDoc()) {
1855 : // Update the editable descendant count in the ancestors before we
1856 : // lose the reference to the parent.
1857 35 : int32_t editableDescendantChange = -1 * EditableInclusiveDescendantCount(this);
1858 35 : if (editableDescendantChange != 0) {
1859 0 : nsIContent* parent = GetParent();
1860 0 : while (parent) {
1861 0 : parent->ChangeEditableDescendantCount(editableDescendantChange);
1862 0 : parent = parent->GetParent();
1863 : }
1864 : }
1865 : }
1866 :
1867 511 : if (this->IsRootOfNativeAnonymousSubtree()) {
1868 4 : nsNodeUtils::NativeAnonymousChildListChange(this, true);
1869 : }
1870 :
1871 511 : if (GetParent()) {
1872 966 : RefPtr<nsINode> p;
1873 483 : p.swap(mParent);
1874 : } else {
1875 28 : mParent = nullptr;
1876 : }
1877 511 : SetParentIsContent(false);
1878 : }
1879 :
1880 : #ifdef DEBUG
1881 : // If we can get access to the PresContext, then we sanity-check that
1882 : // we're not leaving behind a pointer to ourselves as the PresContext's
1883 : // cached provider of the viewport's scrollbar styles.
1884 912 : if (document) {
1885 66 : nsIPresShell* presShell = document->GetShell();
1886 66 : if (presShell) {
1887 66 : nsPresContext* presContext = presShell->GetPresContext();
1888 66 : if (presContext) {
1889 66 : MOZ_ASSERT(this !=
1890 : presContext->GetViewportScrollbarStylesOverrideNode(),
1891 : "Leaving behind a raw pointer to this node (as having "
1892 : "propagated scrollbar styles) - that's dangerous...");
1893 : }
1894 : }
1895 : }
1896 : #endif
1897 :
1898 : // Ensure that CSS transitions don't continue on an element at a
1899 : // different place in the tree (even if reinserted before next
1900 : // animation refresh).
1901 : // We need to delete the properties while we're still in document
1902 : // (if we were in document).
1903 : // FIXME (Bug 522599): Need a test for this.
1904 912 : if (MayHaveAnimations()) {
1905 0 : DeleteProperty(nsGkAtoms::transitionsOfBeforeProperty);
1906 0 : DeleteProperty(nsGkAtoms::transitionsOfAfterProperty);
1907 0 : DeleteProperty(nsGkAtoms::transitionsProperty);
1908 0 : DeleteProperty(nsGkAtoms::animationsOfBeforeProperty);
1909 0 : DeleteProperty(nsGkAtoms::animationsOfAfterProperty);
1910 0 : DeleteProperty(nsGkAtoms::animationsProperty);
1911 : }
1912 :
1913 912 : ClearInDocument();
1914 :
1915 : // Computed styled data isn't useful for detached nodes, and we'll need to
1916 : // recomputed it anyway if we ever insert the nodes back into a document.
1917 912 : if (IsStyledByServo()) {
1918 0 : ClearServoData();
1919 : } else {
1920 912 : MOZ_ASSERT(!HasServoData());
1921 : }
1922 :
1923 : // Editable descendant count only counts descendants that
1924 : // are in the uncomposed document.
1925 912 : ResetEditableDescendantCount();
1926 :
1927 912 : if (aNullParent || !mParent->IsInShadowTree()) {
1928 912 : UnsetFlags(NODE_IS_IN_SHADOW_TREE);
1929 :
1930 : // Begin keeping track of our subtree root.
1931 912 : SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
1932 : }
1933 :
1934 912 : if (document) {
1935 : // Notify XBL- & nsIAnonymousContentCreator-generated
1936 : // anonymous content that the document is changing.
1937 : // Unlike XBL, bindings for web components shadow DOM
1938 : // do not get uninstalled.
1939 66 : if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) && !GetShadowRoot()) {
1940 : nsContentUtils::AddScriptRunner(
1941 12 : new RemoveFromBindingManagerRunnable(document->BindingManager(), this,
1942 12 : document));
1943 : }
1944 :
1945 66 : document->ClearBoxObjectFor(this);
1946 :
1947 : // Detached must be enqueued whenever custom element is removed from
1948 : // the document and this document has a browsing context.
1949 66 : if (GetCustomElementData() && document->GetDocShell()) {
1950 : // Enqueue a detached callback for the custom element.
1951 : nsContentUtils::EnqueueLifecycleCallback(
1952 0 : document, nsIDocument::eDetached, this);
1953 : }
1954 : }
1955 :
1956 : // Unset this since that's what the old code effectively did.
1957 912 : UnsetFlags(NODE_FORCE_XBL_BINDINGS);
1958 912 : bool clearBindingParent = true;
1959 :
1960 : #ifdef MOZ_XUL
1961 912 : nsXULElement* xulElem = nsXULElement::FromContent(this);
1962 912 : if (xulElem) {
1963 716 : xulElem->SetXULBindingParent(nullptr);
1964 716 : clearBindingParent = false;
1965 : }
1966 : #endif
1967 :
1968 912 : nsDOMSlots* slots = GetExistingDOMSlots();
1969 912 : if (slots) {
1970 49 : if (clearBindingParent) {
1971 29 : slots->mBindingParent = nullptr;
1972 : }
1973 49 : if (aNullParent || !mParent->IsInShadowTree()) {
1974 49 : slots->mContainingShadow = nullptr;
1975 : }
1976 : }
1977 :
1978 : // This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree,
1979 : // because it has to happen after unsetting the parent pointer, but before
1980 : // recursively unbinding the kids.
1981 912 : if (IsHTMLElement()) {
1982 10 : ResetDir(this);
1983 : }
1984 :
1985 912 : if (aDeep) {
1986 : // Do the kids. Don't call GetChildCount() here since that'll force
1987 : // XUL to generate template children, which there is no need for since
1988 : // all we're going to do is unbind them anyway.
1989 907 : uint32_t i, n = mAttrsAndChildren.ChildCount();
1990 :
1991 1339 : for (i = 0; i < n; ++i) {
1992 : // Note that we pass false for aNullParent here, since we don't want
1993 : // the kids to forget us. We _do_ want them to forget their binding
1994 : // parent, though, since this only walks non-anonymous kids.
1995 432 : mAttrsAndChildren.ChildAt(i)->UnbindFromTree(true, false);
1996 : }
1997 : }
1998 :
1999 912 : nsNodeUtils::ParentChainChanged(this);
2000 :
2001 : // Unbind children of shadow root.
2002 912 : ShadowRoot* shadowRoot = GetShadowRoot();
2003 912 : if (shadowRoot) {
2004 0 : for (nsIContent* child = shadowRoot->GetFirstChild(); child;
2005 0 : child = child->GetNextSibling()) {
2006 0 : child->UnbindFromTree(true, false);
2007 : }
2008 :
2009 0 : shadowRoot->SetIsComposedDocParticipant(false);
2010 : }
2011 912 : }
2012 :
2013 : nsICSSDeclaration*
2014 0 : Element::GetSMILOverrideStyle()
2015 : {
2016 0 : Element::nsDOMSlots *slots = DOMSlots();
2017 :
2018 0 : if (!slots->mSMILOverrideStyle) {
2019 0 : slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true);
2020 : }
2021 :
2022 0 : return slots->mSMILOverrideStyle;
2023 : }
2024 :
2025 : DeclarationBlock*
2026 2504 : Element::GetSMILOverrideStyleDeclaration()
2027 : {
2028 2504 : Element::nsDOMSlots *slots = GetExistingDOMSlots();
2029 2504 : return slots ? slots->mSMILOverrideStyleDeclaration.get() : nullptr;
2030 : }
2031 :
2032 : nsresult
2033 0 : Element::SetSMILOverrideStyleDeclaration(DeclarationBlock* aDeclaration,
2034 : bool aNotify)
2035 : {
2036 0 : Element::nsDOMSlots *slots = DOMSlots();
2037 :
2038 0 : slots->mSMILOverrideStyleDeclaration = aDeclaration;
2039 :
2040 0 : if (aNotify) {
2041 0 : nsIDocument* doc = GetComposedDoc();
2042 : // Only need to request a restyle if we're in a document. (We might not
2043 : // be in a document, if we're clearing animation effects on a target node
2044 : // that's been detached since the previous animation sample.)
2045 0 : if (doc) {
2046 0 : nsCOMPtr<nsIPresShell> shell = doc->GetShell();
2047 0 : if (shell) {
2048 0 : shell->RestyleForAnimation(this, eRestyle_StyleAttribute_Animations);
2049 : }
2050 : }
2051 : }
2052 :
2053 0 : return NS_OK;
2054 : }
2055 :
2056 : bool
2057 0 : Element::IsLabelable() const
2058 : {
2059 0 : return false;
2060 : }
2061 :
2062 : bool
2063 0 : Element::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
2064 : {
2065 0 : return false;
2066 : }
2067 :
2068 : DeclarationBlock*
2069 2532 : Element::GetInlineStyleDeclaration() const
2070 : {
2071 2532 : if (!MayHaveStyle()) {
2072 2468 : return nullptr;
2073 : }
2074 64 : const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
2075 :
2076 64 : if (attrVal && attrVal->Type() == nsAttrValue::eCSSDeclaration) {
2077 35 : return attrVal->GetCSSDeclarationValue();
2078 : }
2079 :
2080 29 : return nullptr;
2081 : }
2082 :
2083 : const nsMappedAttributes*
2084 0 : Element::GetMappedAttributes() const
2085 : {
2086 0 : return mAttrsAndChildren.GetMapped();
2087 : }
2088 :
2089 : nsresult
2090 0 : Element::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
2091 : const nsAString* aSerialized,
2092 : bool aNotify)
2093 : {
2094 0 : NS_NOTYETIMPLEMENTED("Element::SetInlineStyleDeclaration");
2095 0 : return NS_ERROR_NOT_IMPLEMENTED;
2096 : }
2097 :
2098 : NS_IMETHODIMP_(bool)
2099 1137 : Element::IsAttributeMapped(const nsIAtom* aAttribute) const
2100 : {
2101 1137 : return false;
2102 : }
2103 :
2104 : nsChangeHint
2105 1 : Element::GetAttributeChangeHint(const nsIAtom* aAttribute,
2106 : int32_t aModType) const
2107 : {
2108 1 : return nsChangeHint(0);
2109 : }
2110 :
2111 : bool
2112 1861 : Element::FindAttributeDependence(const nsIAtom* aAttribute,
2113 : const MappedAttributeEntry* const aMaps[],
2114 : uint32_t aMapCount)
2115 : {
2116 7847 : for (uint32_t mapindex = 0; mapindex < aMapCount; ++mapindex) {
2117 40645 : for (const MappedAttributeEntry* map = aMaps[mapindex];
2118 40645 : map->attribute; ++map) {
2119 34659 : if (aAttribute == *map->attribute) {
2120 192 : return true;
2121 : }
2122 : }
2123 : }
2124 :
2125 1669 : return false;
2126 : }
2127 :
2128 : already_AddRefed<mozilla::dom::NodeInfo>
2129 2 : Element::GetExistingAttrNameFromQName(const nsAString& aStr) const
2130 : {
2131 2 : const nsAttrName* name = InternalGetAttrNameFromQName(aStr);
2132 2 : if (!name) {
2133 0 : return nullptr;
2134 : }
2135 :
2136 4 : RefPtr<mozilla::dom::NodeInfo> nodeInfo;
2137 2 : if (name->IsAtom()) {
2138 : nodeInfo = mNodeInfo->NodeInfoManager()->
2139 4 : GetNodeInfo(name->Atom(), nullptr, kNameSpaceID_None,
2140 2 : nsIDOMNode::ATTRIBUTE_NODE);
2141 : }
2142 : else {
2143 0 : nodeInfo = name->NodeInfo();
2144 : }
2145 :
2146 2 : return nodeInfo.forget();
2147 : }
2148 :
2149 : // static
2150 : bool
2151 0 : Element::ShouldBlur(nsIContent *aContent)
2152 : {
2153 : // Determine if the current element is focused, if it is not focused
2154 : // then we should not try to blur
2155 0 : nsIDocument* document = aContent->GetComposedDoc();
2156 0 : if (!document)
2157 0 : return false;
2158 :
2159 0 : nsCOMPtr<nsPIDOMWindowOuter> window = document->GetWindow();
2160 0 : if (!window)
2161 0 : return false;
2162 :
2163 0 : nsCOMPtr<nsPIDOMWindowOuter> focusedFrame;
2164 : nsIContent* contentToBlur =
2165 0 : nsFocusManager::GetFocusedDescendant(window, false, getter_AddRefs(focusedFrame));
2166 0 : if (contentToBlur == aContent)
2167 0 : return true;
2168 :
2169 : // if focus on this element would get redirected, then check the redirected
2170 : // content as well when blurring.
2171 0 : return (contentToBlur && nsFocusManager::GetRedirectedFocus(aContent) == contentToBlur);
2172 : }
2173 :
2174 : bool
2175 4888 : Element::IsNodeOfType(uint32_t aFlags) const
2176 : {
2177 4888 : return !(aFlags & ~eCONTENT);
2178 : }
2179 :
2180 : /* static */
2181 : nsresult
2182 0 : Element::DispatchEvent(nsPresContext* aPresContext,
2183 : WidgetEvent* aEvent,
2184 : nsIContent* aTarget,
2185 : bool aFullDispatch,
2186 : nsEventStatus* aStatus)
2187 : {
2188 0 : NS_PRECONDITION(aTarget, "Must have target");
2189 0 : NS_PRECONDITION(aEvent, "Must have source event");
2190 0 : NS_PRECONDITION(aStatus, "Null out param?");
2191 :
2192 0 : if (!aPresContext) {
2193 0 : return NS_OK;
2194 : }
2195 :
2196 0 : nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
2197 0 : if (!shell) {
2198 0 : return NS_OK;
2199 : }
2200 :
2201 0 : if (aFullDispatch) {
2202 0 : return shell->HandleEventWithTarget(aEvent, nullptr, aTarget, aStatus);
2203 : }
2204 :
2205 0 : return shell->HandleDOMEventWithTarget(aTarget, aEvent, aStatus);
2206 : }
2207 :
2208 : /* static */
2209 : nsresult
2210 0 : Element::DispatchClickEvent(nsPresContext* aPresContext,
2211 : WidgetInputEvent* aSourceEvent,
2212 : nsIContent* aTarget,
2213 : bool aFullDispatch,
2214 : const EventFlags* aExtraEventFlags,
2215 : nsEventStatus* aStatus)
2216 : {
2217 0 : NS_PRECONDITION(aTarget, "Must have target");
2218 0 : NS_PRECONDITION(aSourceEvent, "Must have source event");
2219 0 : NS_PRECONDITION(aStatus, "Null out param?");
2220 :
2221 0 : WidgetMouseEvent event(aSourceEvent->IsTrusted(), eMouseClick,
2222 0 : aSourceEvent->mWidget, WidgetMouseEvent::eReal);
2223 0 : event.mRefPoint = aSourceEvent->mRefPoint;
2224 0 : uint32_t clickCount = 1;
2225 0 : float pressure = 0;
2226 0 : uint32_t pointerId = 0; // Use the default value here.
2227 0 : uint16_t inputSource = 0;
2228 0 : WidgetMouseEvent* sourceMouseEvent = aSourceEvent->AsMouseEvent();
2229 0 : if (sourceMouseEvent) {
2230 0 : clickCount = sourceMouseEvent->mClickCount;
2231 0 : pressure = sourceMouseEvent->pressure;
2232 0 : pointerId = sourceMouseEvent->pointerId;
2233 0 : inputSource = sourceMouseEvent->inputSource;
2234 0 : } else if (aSourceEvent->mClass == eKeyboardEventClass) {
2235 0 : event.mFlags.mIsPositionless = true;
2236 0 : inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
2237 : }
2238 0 : event.pressure = pressure;
2239 0 : event.mClickCount = clickCount;
2240 0 : event.pointerId = pointerId;
2241 0 : event.inputSource = inputSource;
2242 0 : event.mModifiers = aSourceEvent->mModifiers;
2243 0 : if (aExtraEventFlags) {
2244 : // Be careful not to overwrite existing flags!
2245 0 : event.mFlags.Union(*aExtraEventFlags);
2246 : }
2247 :
2248 0 : return DispatchEvent(aPresContext, &event, aTarget, aFullDispatch, aStatus);
2249 : }
2250 :
2251 : nsIFrame*
2252 4 : Element::GetPrimaryFrame(FlushType aType)
2253 : {
2254 4 : nsIDocument* doc = GetComposedDoc();
2255 4 : if (!doc) {
2256 0 : return nullptr;
2257 : }
2258 :
2259 : // Cause a flush, so we get up-to-date frame
2260 : // information
2261 4 : if (aType != FlushType::None) {
2262 4 : doc->FlushPendingNotifications(aType);
2263 : }
2264 :
2265 4 : return GetPrimaryFrame();
2266 : }
2267 :
2268 : //----------------------------------------------------------------------
2269 : nsresult
2270 0 : Element::LeaveLink(nsPresContext* aPresContext)
2271 : {
2272 0 : nsILinkHandler *handler = aPresContext->GetLinkHandler();
2273 0 : if (!handler) {
2274 0 : return NS_OK;
2275 : }
2276 :
2277 0 : return handler->OnLeaveLink();
2278 : }
2279 :
2280 : nsresult
2281 554 : Element::SetEventHandler(nsIAtom* aEventName,
2282 : const nsAString& aValue,
2283 : bool aDefer)
2284 : {
2285 554 : nsIDocument *ownerDoc = OwnerDoc();
2286 554 : if (ownerDoc->IsLoadedAsData()) {
2287 : // Make this a no-op rather than throwing an error to avoid
2288 : // the error causing problems setting the attribute.
2289 0 : return NS_OK;
2290 : }
2291 :
2292 554 : NS_PRECONDITION(aEventName, "Must have event name!");
2293 554 : bool defer = true;
2294 : EventListenerManager* manager =
2295 554 : GetEventListenerManagerForAttr(aEventName, &defer);
2296 554 : if (!manager) {
2297 0 : return NS_OK;
2298 : }
2299 :
2300 554 : defer = defer && aDefer; // only defer if everyone agrees...
2301 554 : manager->SetEventHandler(aEventName, aValue,
2302 554 : defer, !nsContentUtils::IsChromeDoc(ownerDoc),
2303 554 : this);
2304 554 : return NS_OK;
2305 : }
2306 :
2307 :
2308 : //----------------------------------------------------------------------
2309 :
2310 : const nsAttrName*
2311 502 : Element::InternalGetAttrNameFromQName(const nsAString& aStr,
2312 : nsAutoString* aNameToUse) const
2313 : {
2314 502 : MOZ_ASSERT(!aNameToUse || aNameToUse->IsEmpty());
2315 502 : const nsAttrName* val = nullptr;
2316 502 : if (IsHTMLElement() && IsInHTMLDocument()) {
2317 2 : nsAutoString lower;
2318 1 : nsAutoString& outStr = aNameToUse ? *aNameToUse : lower;
2319 1 : nsContentUtils::ASCIIToLower(aStr, outStr);
2320 1 : val = mAttrsAndChildren.GetExistingAttrNameFromQName(outStr);
2321 1 : if (val) {
2322 0 : outStr.Truncate();
2323 : }
2324 : } else {
2325 501 : val = mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
2326 501 : if (!val && aNameToUse) {
2327 277 : *aNameToUse = aStr;
2328 : }
2329 : }
2330 :
2331 502 : return val;
2332 : }
2333 :
2334 : bool
2335 1917 : Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
2336 : nsIAtom* aName,
2337 : nsIAtom* aPrefix,
2338 : const nsAttrValueOrString& aValue,
2339 : bool aNotify,
2340 : nsAttrValue& aOldValue,
2341 : uint8_t* aModType,
2342 : bool* aHasListeners,
2343 : bool* aOldValueSet)
2344 : {
2345 1917 : bool modification = false;
2346 2568 : *aHasListeners = aNotify &&
2347 651 : nsContentUtils::HasMutationListeners(this,
2348 : NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
2349 : this);
2350 1917 : *aOldValueSet = false;
2351 :
2352 : // If we have no listeners and aNotify is false, we are almost certainly
2353 : // coming from the content sink and will almost certainly have no previous
2354 : // value. Even if we do, setting the value is cheap when we have no
2355 : // listeners and don't plan to notify. The check for aNotify here is an
2356 : // optimization, the check for *aHasListeners is a correctness issue.
2357 1917 : if (*aHasListeners || aNotify) {
2358 651 : BorrowedAttrInfo info(GetAttrInfo(aNamespaceID, aName));
2359 651 : if (info.mValue) {
2360 : // Check whether the old value is the same as the new one. Note that we
2361 : // only need to actually _get_ the old value if we have listeners or
2362 : // if the element is a custom element (because it may have an
2363 : // attribute changed callback).
2364 134 : if (*aHasListeners || GetCustomElementData()) {
2365 : // Need to store the old value.
2366 : //
2367 : // If the current attribute value contains a pointer to some other data
2368 : // structure that gets updated in the process of setting the attribute
2369 : // we'll no longer have the old value of the attribute. Therefore, we
2370 : // should serialize the attribute value now to keep a snapshot.
2371 : //
2372 : // We have to serialize the value anyway in order to create the
2373 : // mutation event so there's no cost in doing it now.
2374 0 : aOldValue.SetToSerialized(*info.mValue);
2375 0 : *aOldValueSet = true;
2376 : }
2377 134 : bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
2378 134 : if (valueMatches && aPrefix == info.mName->GetPrefix()) {
2379 101 : return true;
2380 : }
2381 33 : modification = true;
2382 : }
2383 : }
2384 1816 : *aModType = modification ?
2385 : static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) :
2386 : static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
2387 1816 : return false;
2388 : }
2389 :
2390 : bool
2391 1917 : Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
2392 : nsIAtom* aPrefix,
2393 : const nsAttrValueOrString& aValue,
2394 : bool aNotify, nsAttrValue& aOldValue,
2395 : uint8_t* aModType, bool* aHasListeners,
2396 : bool* aOldValueSet)
2397 : {
2398 1917 : if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
2399 : aOldValue, aModType, aHasListeners,
2400 : aOldValueSet)) {
2401 1816 : return false;
2402 : }
2403 :
2404 202 : nsAutoScriptBlocker scriptBlocker;
2405 101 : nsNodeUtils::AttributeSetToCurrentValue(this, aNamespaceID, aName);
2406 101 : return true;
2407 : }
2408 :
2409 : nsresult
2410 1917 : Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
2411 : nsIAtom* aPrefix, const nsAString& aValue,
2412 : bool aNotify)
2413 : {
2414 : // Keep this in sync with SetParsedAttr below
2415 :
2416 1917 : NS_ENSURE_ARG_POINTER(aName);
2417 1917 : NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
2418 : "Don't call SetAttr with unknown namespace");
2419 :
2420 1917 : if (!mAttrsAndChildren.CanFitMoreAttrs()) {
2421 0 : return NS_ERROR_FAILURE;
2422 : }
2423 :
2424 : uint8_t modType;
2425 : bool hasListeners;
2426 : // We don't want to spend time preparsing class attributes if the value is not
2427 : // changing, so just init our nsAttrValueOrString with aValue for the
2428 : // OnlyNotifySameValueSet call.
2429 3834 : nsAttrValueOrString value(aValue);
2430 3834 : nsAttrValue oldValue;
2431 : bool oldValueSet;
2432 :
2433 1917 : if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
2434 : oldValue, &modType, &hasListeners, &oldValueSet)) {
2435 101 : return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
2436 : }
2437 :
2438 3632 : nsAttrValue attrValue;
2439 : nsAttrValue* preparsedAttrValue;
2440 1816 : if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::_class) {
2441 90 : attrValue.ParseAtomArray(aValue);
2442 90 : value.ResetToAttrValue(attrValue);
2443 90 : preparsedAttrValue = &attrValue;
2444 : } else {
2445 1726 : preparsedAttrValue = nullptr;
2446 : }
2447 :
2448 1816 : if (aNotify) {
2449 550 : nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
2450 550 : preparsedAttrValue);
2451 : }
2452 :
2453 : // Hold a script blocker while calling ParseAttribute since that can call
2454 : // out to id-observers
2455 1816 : nsIDocument* document = GetComposedDoc();
2456 3632 : mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
2457 :
2458 1816 : nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
2459 1816 : NS_ENSURE_SUCCESS(rv, rv);
2460 :
2461 3542 : if (!preparsedAttrValue &&
2462 1726 : !ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
2463 466 : attrValue.SetTo(aValue);
2464 : }
2465 :
2466 1816 : PreIdMaybeChange(aNamespaceID, aName, &value);
2467 :
2468 1816 : return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
2469 : oldValueSet ? &oldValue : nullptr,
2470 : attrValue, modType, hasListeners, aNotify,
2471 1816 : kCallAfterSetAttr, document, updateBatch);
2472 : }
2473 :
2474 : nsresult
2475 0 : Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
2476 : nsIAtom* aPrefix, nsAttrValue& aParsedValue,
2477 : bool aNotify)
2478 : {
2479 : // Keep this in sync with SetAttr above
2480 :
2481 0 : NS_ENSURE_ARG_POINTER(aName);
2482 0 : NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
2483 : "Don't call SetAttr with unknown namespace");
2484 :
2485 0 : if (!mAttrsAndChildren.CanFitMoreAttrs()) {
2486 0 : return NS_ERROR_FAILURE;
2487 : }
2488 :
2489 :
2490 : uint8_t modType;
2491 : bool hasListeners;
2492 0 : nsAttrValueOrString value(aParsedValue);
2493 0 : nsAttrValue oldValue;
2494 : bool oldValueSet;
2495 :
2496 0 : if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
2497 : oldValue, &modType, &hasListeners, &oldValueSet)) {
2498 0 : return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
2499 : }
2500 :
2501 0 : if (aNotify) {
2502 0 : nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
2503 0 : &aParsedValue);
2504 : }
2505 :
2506 0 : nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
2507 0 : NS_ENSURE_SUCCESS(rv, rv);
2508 :
2509 0 : PreIdMaybeChange(aNamespaceID, aName, &value);
2510 :
2511 0 : nsIDocument* document = GetComposedDoc();
2512 0 : mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
2513 0 : return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
2514 : oldValueSet ? &oldValue : nullptr,
2515 : aParsedValue, modType, hasListeners, aNotify,
2516 0 : kCallAfterSetAttr, document, updateBatch);
2517 : }
2518 :
2519 : nsresult
2520 1825 : Element::SetAttrAndNotify(int32_t aNamespaceID,
2521 : nsIAtom* aName,
2522 : nsIAtom* aPrefix,
2523 : const nsAttrValue* aOldValue,
2524 : nsAttrValue& aParsedValue,
2525 : uint8_t aModType,
2526 : bool aFireMutation,
2527 : bool aNotify,
2528 : bool aCallAfterSetAttr,
2529 : nsIDocument* aComposedDocument,
2530 : const mozAutoDocUpdate&)
2531 : {
2532 : nsresult rv;
2533 1825 : nsMutationGuard::DidMutate();
2534 :
2535 : // Copy aParsedValue for later use since it will be lost when we call
2536 : // SetAndSwapMappedAttr below
2537 3650 : nsAttrValue valueForAfterSetAttr;
2538 1825 : if (aCallAfterSetAttr) {
2539 1816 : valueForAfterSetAttr.SetTo(aParsedValue);
2540 : }
2541 :
2542 1825 : bool hadValidDir = false;
2543 1825 : bool hadDirAuto = false;
2544 : bool oldValueSet;
2545 :
2546 1825 : if (aNamespaceID == kNameSpaceID_None) {
2547 1742 : if (aName == nsGkAtoms::dir) {
2548 0 : hadValidDir = HasValidDir() || IsHTMLElement(nsGkAtoms::bdi);
2549 0 : hadDirAuto = HasDirAuto(); // already takes bdi into account
2550 : }
2551 :
2552 : // XXXbz Perhaps we should push up the attribute mapping function
2553 : // stuff to Element?
2554 1865 : if (!IsAttributeMapped(aName) ||
2555 123 : !SetAndSwapMappedAttribute(aName, aParsedValue, &oldValueSet, &rv)) {
2556 1716 : rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
2557 : }
2558 : }
2559 : else {
2560 166 : RefPtr<mozilla::dom::NodeInfo> ni;
2561 166 : ni = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix,
2562 : aNamespaceID,
2563 83 : nsIDOMNode::ATTRIBUTE_NODE);
2564 :
2565 83 : rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
2566 : }
2567 1825 : NS_ENSURE_SUCCESS(rv, rv);
2568 :
2569 1825 : PostIdMaybeChange(aNamespaceID, aName, &valueForAfterSetAttr);
2570 :
2571 : // If the old value owns its own data, we know it is OK to keep using it.
2572 : // oldValue will be null if there was no previously set value
2573 : const nsAttrValue* oldValue;
2574 1825 : if (aParsedValue.StoresOwnData()) {
2575 1820 : if (oldValueSet) {
2576 78 : oldValue = &aParsedValue;
2577 : } else {
2578 1742 : oldValue = nullptr;
2579 : }
2580 : } else {
2581 : // No need to conditionally assign null here. If there was no previously
2582 : // set value for the attribute, aOldValue will already be null.
2583 5 : oldValue = aOldValue;
2584 : }
2585 :
2586 1825 : if (aComposedDocument || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
2587 1638 : RefPtr<nsXBLBinding> binding = GetXBLBinding();
2588 819 : if (binding) {
2589 210 : binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
2590 : }
2591 : }
2592 :
2593 1825 : nsIDocument* ownerDoc = OwnerDoc();
2594 1825 : if (ownerDoc && GetCustomElementData()) {
2595 0 : nsCOMPtr<nsIAtom> oldValueAtom;
2596 0 : if (oldValue) {
2597 0 : oldValueAtom = oldValue->GetAsAtom();
2598 : } else {
2599 : // If there is no old value, get the value of the uninitialized attribute
2600 : // that was swapped with aParsedValue.
2601 0 : oldValueAtom = aParsedValue.GetAsAtom();
2602 : }
2603 0 : nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
2604 : LifecycleCallbackArgs args = {
2605 0 : nsDependentAtomString(aName),
2606 : aModType == nsIDOMMutationEvent::ADDITION ?
2607 0 : NullString() : nsDependentAtomString(oldValueAtom),
2608 0 : nsDependentAtomString(newValueAtom)
2609 0 : };
2610 :
2611 : nsContentUtils::EnqueueLifecycleCallback(
2612 0 : ownerDoc, nsIDocument::eAttributeChanged, this, &args);
2613 : }
2614 :
2615 1825 : if (aCallAfterSetAttr) {
2616 1816 : rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, oldValue,
2617 1816 : aNotify);
2618 1816 : NS_ENSURE_SUCCESS(rv, rv);
2619 :
2620 1816 : if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
2621 0 : OnSetDirAttr(this, &valueForAfterSetAttr,
2622 0 : hadValidDir, hadDirAuto, aNotify);
2623 : }
2624 : }
2625 :
2626 1825 : UpdateState(aNotify);
2627 :
2628 1825 : if (aNotify) {
2629 : // Don't pass aOldValue to AttributeChanged since it may not be reliable.
2630 : // Callers only compute aOldValue under certain conditions which may not
2631 : // be triggered by all nsIMutationObservers.
2632 555 : nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType,
2633 1110 : aParsedValue.StoresOwnData() ? &aParsedValue : nullptr);
2634 : }
2635 :
2636 1825 : if (aFireMutation) {
2637 0 : InternalMutationEvent mutation(true, eLegacyAttrModified);
2638 :
2639 0 : nsAutoString ns;
2640 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
2641 : Attr* attrNode =
2642 0 : GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName));
2643 0 : mutation.mRelatedNode = attrNode;
2644 :
2645 0 : mutation.mAttrName = aName;
2646 0 : nsAutoString newValue;
2647 0 : GetAttr(aNamespaceID, aName, newValue);
2648 0 : if (!newValue.IsEmpty()) {
2649 0 : mutation.mNewAttrValue = NS_Atomize(newValue);
2650 : }
2651 0 : if (oldValue && !oldValue->IsEmptyString()) {
2652 0 : mutation.mPrevAttrValue = oldValue->GetAsAtom();
2653 : }
2654 0 : mutation.mAttrChange = aModType;
2655 :
2656 0 : mozAutoSubtreeModified subtree(OwnerDoc(), this);
2657 0 : (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
2658 : }
2659 :
2660 1825 : return NS_OK;
2661 : }
2662 :
2663 : bool
2664 1498 : Element::ParseAttribute(int32_t aNamespaceID,
2665 : nsIAtom* aAttribute,
2666 : const nsAString& aValue,
2667 : nsAttrValue& aResult)
2668 : {
2669 1498 : if (aAttribute == nsGkAtoms::lang) {
2670 0 : aResult.ParseAtom(aValue);
2671 0 : return true;
2672 : }
2673 :
2674 1498 : if (aNamespaceID == kNameSpaceID_None) {
2675 1438 : MOZ_ASSERT(aAttribute != nsGkAtoms::_class,
2676 : "The class attribute should be preparsed and therefore should "
2677 : "never be passed to Element::ParseAttribute");
2678 1438 : if (aAttribute == nsGkAtoms::id) {
2679 : // Store id as an atom. id="" means that the element has no id,
2680 : // not that it has an emptystring as the id.
2681 116 : if (aValue.IsEmpty()) {
2682 0 : return false;
2683 : }
2684 116 : aResult.ParseAtom(aValue);
2685 116 : return true;
2686 : }
2687 : }
2688 :
2689 1382 : return false;
2690 : }
2691 :
2692 : bool
2693 97 : Element::SetAndSwapMappedAttribute(nsIAtom* aName,
2694 : nsAttrValue& aValue,
2695 : bool* aValueWasSet,
2696 : nsresult* aRetval)
2697 : {
2698 97 : *aRetval = NS_OK;
2699 97 : return false;
2700 : }
2701 :
2702 : nsresult
2703 1952 : Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
2704 : const nsAttrValueOrString* aValue, bool aNotify)
2705 : {
2706 1952 : if (aNamespaceID == kNameSpaceID_None) {
2707 1869 : if (aName == nsGkAtoms::_class) {
2708 90 : if (aValue) {
2709 : // Note: This flag is asymmetrical. It is never unset and isn't exact.
2710 : // If it is ever made to be exact, we probably need to handle this
2711 : // similarly to how ids are handled in PreIdMaybeChange and
2712 : // PostIdMaybeChange.
2713 90 : SetMayHaveClass();
2714 : }
2715 : }
2716 : }
2717 :
2718 1952 : return NS_OK;
2719 : }
2720 :
2721 : void
2722 1952 : Element::PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
2723 : const nsAttrValueOrString* aValue)
2724 : {
2725 1952 : if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
2726 1832 : return;
2727 : }
2728 120 : RemoveFromIdTable();
2729 :
2730 120 : return;
2731 : }
2732 :
2733 : void
2734 1961 : Element::PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
2735 : const nsAttrValue* aValue)
2736 : {
2737 1961 : if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
2738 1841 : return;
2739 : }
2740 :
2741 : // id="" means that the element has no id, not that it has an empty
2742 : // string as the id.
2743 120 : if (aValue && !aValue->IsEmptyString()) {
2744 116 : SetHasID();
2745 116 : AddToIdTable(aValue->GetAtomValue());
2746 : } else {
2747 4 : ClearHasID();
2748 : }
2749 :
2750 120 : return;
2751 : }
2752 :
2753 : EventListenerManager*
2754 551 : Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
2755 : bool* aDefer)
2756 : {
2757 551 : *aDefer = true;
2758 551 : return GetOrCreateListenerManager();
2759 : }
2760 :
2761 : BorrowedAttrInfo
2762 666 : Element::GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const
2763 : {
2764 666 : NS_ASSERTION(nullptr != aName, "must have attribute name");
2765 666 : NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
2766 : "must have a real namespace ID!");
2767 :
2768 666 : int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNamespaceID);
2769 666 : if (index < 0) {
2770 523 : return BorrowedAttrInfo(nullptr, nullptr);
2771 : }
2772 :
2773 143 : return mAttrsAndChildren.AttrInfoAt(index);
2774 : }
2775 :
2776 : BorrowedAttrInfo
2777 242 : Element::GetAttrInfoAt(uint32_t aIndex) const
2778 : {
2779 242 : if (aIndex >= mAttrsAndChildren.AttrCount()) {
2780 150 : return BorrowedAttrInfo(nullptr, nullptr);
2781 : }
2782 :
2783 92 : return mAttrsAndChildren.AttrInfoAt(aIndex);
2784 : }
2785 :
2786 : bool
2787 21268 : Element::GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
2788 : nsAString& aResult) const
2789 : {
2790 42536 : DOMString str;
2791 21268 : bool haveAttr = GetAttr(aNameSpaceID, aName, str);
2792 21268 : str.ToString(aResult);
2793 42536 : return haveAttr;
2794 : }
2795 :
2796 : int32_t
2797 6184 : Element::FindAttrValueIn(int32_t aNameSpaceID,
2798 : nsIAtom* aName,
2799 : AttrValuesArray* aValues,
2800 : nsCaseTreatment aCaseSensitive) const
2801 : {
2802 6184 : NS_ASSERTION(aName, "Must have attr name");
2803 6184 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
2804 6184 : NS_ASSERTION(aValues, "Null value array");
2805 :
2806 6184 : const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
2807 6184 : if (val) {
2808 859 : for (int32_t i = 0; aValues[i]; ++i) {
2809 710 : if (val->Equals(*aValues[i], aCaseSensitive)) {
2810 175 : return i;
2811 : }
2812 : }
2813 149 : return ATTR_VALUE_NO_MATCH;
2814 : }
2815 5860 : return ATTR_MISSING;
2816 : }
2817 :
2818 : nsresult
2819 172 : Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
2820 : bool aNotify)
2821 : {
2822 172 : NS_ASSERTION(nullptr != aName, "must have attribute name");
2823 :
2824 172 : int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
2825 172 : if (index < 0) {
2826 36 : return NS_OK;
2827 : }
2828 :
2829 136 : nsIDocument *document = GetComposedDoc();
2830 272 : mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
2831 :
2832 136 : if (aNotify) {
2833 : nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
2834 : nsIDOMMutationEvent::REMOVAL,
2835 40 : nullptr);
2836 : }
2837 :
2838 136 : nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
2839 136 : NS_ENSURE_SUCCESS(rv, rv);
2840 :
2841 176 : bool hasMutationListeners = aNotify &&
2842 40 : nsContentUtils::HasMutationListeners(this,
2843 : NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
2844 136 : this);
2845 :
2846 136 : PreIdMaybeChange(aNameSpaceID, aName, nullptr);
2847 :
2848 : // Grab the attr node if needed before we remove it from the attr map
2849 272 : RefPtr<Attr> attrNode;
2850 136 : if (hasMutationListeners) {
2851 0 : nsAutoString ns;
2852 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
2853 0 : attrNode = GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName));
2854 : }
2855 :
2856 : // Clear binding to nsIDOMMozNamedAttrMap
2857 136 : nsDOMSlots *slots = GetExistingDOMSlots();
2858 136 : if (slots && slots->mAttributeMap) {
2859 0 : slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
2860 : }
2861 :
2862 : // The id-handling code, and in the future possibly other code, need to
2863 : // react to unexpected attribute changes.
2864 136 : nsMutationGuard::DidMutate();
2865 :
2866 136 : bool hadValidDir = false;
2867 136 : bool hadDirAuto = false;
2868 :
2869 136 : if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
2870 0 : hadValidDir = HasValidDir() || IsHTMLElement(nsGkAtoms::bdi);
2871 0 : hadDirAuto = HasDirAuto(); // already takes bdi into account
2872 : }
2873 :
2874 272 : nsAttrValue oldValue;
2875 136 : rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
2876 136 : NS_ENSURE_SUCCESS(rv, rv);
2877 :
2878 136 : PostIdMaybeChange(aNameSpaceID, aName, nullptr);
2879 :
2880 136 : if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
2881 88 : RefPtr<nsXBLBinding> binding = GetXBLBinding();
2882 44 : if (binding) {
2883 17 : binding->AttributeChanged(aName, aNameSpaceID, true, aNotify);
2884 : }
2885 : }
2886 :
2887 136 : nsIDocument* ownerDoc = OwnerDoc();
2888 136 : if (ownerDoc && GetCustomElementData()) {
2889 0 : nsCOMPtr<nsIAtom> oldValueAtom = oldValue.GetAsAtom();
2890 : LifecycleCallbackArgs args = {
2891 0 : nsDependentAtomString(aName),
2892 0 : nsDependentAtomString(oldValueAtom),
2893 0 : NullString()
2894 0 : };
2895 :
2896 : nsContentUtils::EnqueueLifecycleCallback(
2897 0 : ownerDoc, nsIDocument::eAttributeChanged, this, &args);
2898 : }
2899 :
2900 136 : rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, aNotify);
2901 136 : NS_ENSURE_SUCCESS(rv, rv);
2902 :
2903 136 : UpdateState(aNotify);
2904 :
2905 136 : if (aNotify) {
2906 : // We can always pass oldValue here since there is no new value which could
2907 : // have corrupted it.
2908 : nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
2909 40 : nsIDOMMutationEvent::REMOVAL, &oldValue);
2910 : }
2911 :
2912 136 : if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
2913 0 : OnSetDirAttr(this, nullptr, hadValidDir, hadDirAuto, aNotify);
2914 : }
2915 :
2916 136 : if (hasMutationListeners) {
2917 0 : InternalMutationEvent mutation(true, eLegacyAttrModified);
2918 :
2919 0 : mutation.mRelatedNode = attrNode;
2920 0 : mutation.mAttrName = aName;
2921 :
2922 0 : nsAutoString value;
2923 0 : oldValue.ToString(value);
2924 0 : if (!value.IsEmpty())
2925 0 : mutation.mPrevAttrValue = NS_Atomize(value);
2926 0 : mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
2927 :
2928 0 : mozAutoSubtreeModified subtree(OwnerDoc(), this);
2929 0 : (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
2930 : }
2931 :
2932 136 : return NS_OK;
2933 : }
2934 :
2935 : const nsAttrName*
2936 322 : Element::GetAttrNameAt(uint32_t aIndex) const
2937 : {
2938 322 : return mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
2939 : }
2940 :
2941 : uint32_t
2942 94 : Element::GetAttrCount() const
2943 : {
2944 94 : return mAttrsAndChildren.AttrCount();
2945 : }
2946 :
2947 : void
2948 0 : Element::DescribeAttribute(uint32_t index, nsAString& aOutDescription) const
2949 : {
2950 : // name
2951 0 : mAttrsAndChildren.AttrNameAt(index)->GetQualifiedName(aOutDescription);
2952 :
2953 : // value
2954 0 : aOutDescription.AppendLiteral("=\"");
2955 0 : nsAutoString value;
2956 0 : mAttrsAndChildren.AttrAt(index)->ToString(value);
2957 0 : for (uint32_t i = value.Length(); i > 0; --i) {
2958 0 : if (value[i - 1] == char16_t('"'))
2959 0 : value.Insert(char16_t('\\'), i - 1);
2960 : }
2961 0 : aOutDescription.Append(value);
2962 0 : aOutDescription.Append('"');
2963 0 : }
2964 :
2965 : #ifdef DEBUG
2966 : void
2967 0 : Element::ListAttributes(FILE* out) const
2968 : {
2969 0 : uint32_t index, count = mAttrsAndChildren.AttrCount();
2970 0 : for (index = 0; index < count; index++) {
2971 0 : nsAutoString attributeDescription;
2972 0 : DescribeAttribute(index, attributeDescription);
2973 :
2974 0 : fputs(" ", out);
2975 0 : fputs(NS_LossyConvertUTF16toASCII(attributeDescription).get(), out);
2976 : }
2977 0 : }
2978 :
2979 : void
2980 0 : Element::List(FILE* out, int32_t aIndent,
2981 : const nsCString& aPrefix) const
2982 : {
2983 : int32_t indent;
2984 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
2985 :
2986 0 : fputs(aPrefix.get(), out);
2987 :
2988 0 : fputs(NS_LossyConvertUTF16toASCII(mNodeInfo->QualifiedName()).get(), out);
2989 :
2990 0 : fprintf(out, "@%p", (void *)this);
2991 :
2992 0 : ListAttributes(out);
2993 :
2994 : fprintf(out, " state=[%llx]",
2995 0 : static_cast<unsigned long long>(State().GetInternalValue()));
2996 0 : fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
2997 0 : if (IsCommonAncestorForRangeInSelection()) {
2998 : nsRange::RangeHashTable* ranges =
2999 0 : static_cast<nsRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
3000 0 : fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
3001 : }
3002 0 : fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
3003 0 : fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get());
3004 :
3005 0 : nsIContent* child = GetFirstChild();
3006 0 : if (child) {
3007 0 : fputs("\n", out);
3008 :
3009 0 : for (; child; child = child->GetNextSibling()) {
3010 0 : child->List(out, aIndent + 1);
3011 : }
3012 :
3013 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
3014 : }
3015 :
3016 0 : fputs(">\n", out);
3017 :
3018 0 : Element* nonConstThis = const_cast<Element*>(this);
3019 :
3020 : // XXX sXBL/XBL2 issue! Owner or current document?
3021 0 : nsIDocument *document = OwnerDoc();
3022 :
3023 : // Note: not listing nsIAnonymousContentCreator-created content...
3024 :
3025 0 : nsBindingManager* bindingManager = document->BindingManager();
3026 0 : nsCOMPtr<nsIDOMNodeList> anonymousChildren;
3027 0 : bindingManager->GetAnonymousNodesFor(nonConstThis,
3028 0 : getter_AddRefs(anonymousChildren));
3029 :
3030 0 : if (anonymousChildren) {
3031 0 : uint32_t length = 0;
3032 0 : anonymousChildren->GetLength(&length);
3033 :
3034 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
3035 0 : fputs("anonymous-children<\n", out);
3036 :
3037 0 : for (uint32_t i = 0; i < length; ++i) {
3038 0 : nsCOMPtr<nsIDOMNode> node;
3039 0 : anonymousChildren->Item(i, getter_AddRefs(node));
3040 0 : nsCOMPtr<nsIContent> child = do_QueryInterface(node);
3041 0 : child->List(out, aIndent + 1);
3042 : }
3043 :
3044 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
3045 0 : fputs(">\n", out);
3046 :
3047 0 : bool outHeader = false;
3048 0 : ExplicitChildIterator iter(nonConstThis);
3049 0 : for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
3050 0 : if (!outHeader) {
3051 0 : outHeader = true;
3052 :
3053 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
3054 0 : fputs("content-list<\n", out);
3055 : }
3056 :
3057 0 : child->List(out, aIndent + 1);
3058 : }
3059 :
3060 0 : if (outHeader) {
3061 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
3062 0 : fputs(">\n", out);
3063 : }
3064 : }
3065 0 : }
3066 :
3067 : void
3068 0 : Element::DumpContent(FILE* out, int32_t aIndent,
3069 : bool aDumpAll) const
3070 : {
3071 : int32_t indent;
3072 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
3073 :
3074 0 : const nsString& buf = mNodeInfo->QualifiedName();
3075 0 : fputs("<", out);
3076 0 : fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
3077 :
3078 0 : if(aDumpAll) ListAttributes(out);
3079 :
3080 0 : fputs(">", out);
3081 :
3082 0 : if(aIndent) fputs("\n", out);
3083 :
3084 0 : for (nsIContent* child = GetFirstChild();
3085 0 : child;
3086 0 : child = child->GetNextSibling()) {
3087 0 : int32_t indent = aIndent ? aIndent + 1 : 0;
3088 0 : child->DumpContent(out, indent, aDumpAll);
3089 : }
3090 0 : for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
3091 0 : fputs("</", out);
3092 0 : fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
3093 0 : fputs(">", out);
3094 :
3095 0 : if(aIndent) fputs("\n", out);
3096 0 : }
3097 : #endif
3098 :
3099 : void
3100 0 : Element::Describe(nsAString& aOutDescription) const
3101 : {
3102 0 : aOutDescription.Append(mNodeInfo->QualifiedName());
3103 0 : aOutDescription.AppendPrintf("@%p", (void *)this);
3104 :
3105 0 : uint32_t index, count = mAttrsAndChildren.AttrCount();
3106 0 : for (index = 0; index < count; index++) {
3107 0 : aOutDescription.Append(' ');
3108 0 : nsAutoString attributeDescription;
3109 0 : DescribeAttribute(index, attributeDescription);
3110 0 : aOutDescription.Append(attributeDescription);
3111 : }
3112 0 : }
3113 :
3114 : bool
3115 0 : Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
3116 : nsIURI** aURI) const
3117 : {
3118 0 : if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
3119 0 : (!aVisitor.mEvent->IsTrusted() &&
3120 0 : (aVisitor.mEvent->mMessage != eMouseClick) &&
3121 0 : (aVisitor.mEvent->mMessage != eKeyPress) &&
3122 0 : (aVisitor.mEvent->mMessage != eLegacyDOMActivate)) ||
3123 0 : !aVisitor.mPresContext ||
3124 0 : aVisitor.mEvent->mFlags.mMultipleActionsPrevented) {
3125 0 : return false;
3126 : }
3127 :
3128 : // Make sure we actually are a link
3129 0 : return IsLink(aURI);
3130 : }
3131 :
3132 : nsresult
3133 0 : Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor)
3134 : {
3135 : // Optimisation: return early if this event doesn't interest us.
3136 : // IMPORTANT: this switch and the switch below it must be kept in sync!
3137 0 : switch (aVisitor.mEvent->mMessage) {
3138 : case eMouseOver:
3139 : case eFocus:
3140 : case eMouseOut:
3141 : case eBlur:
3142 0 : break;
3143 : default:
3144 0 : return NS_OK;
3145 : }
3146 :
3147 : // Make sure we meet the preconditions before continuing
3148 0 : nsCOMPtr<nsIURI> absURI;
3149 0 : if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
3150 0 : return NS_OK;
3151 : }
3152 :
3153 0 : nsresult rv = NS_OK;
3154 :
3155 : // We do the status bar updates in GetEventTargetParent so that the status bar
3156 : // gets updated even if the event is consumed before we have a chance to set
3157 : // it.
3158 0 : switch (aVisitor.mEvent->mMessage) {
3159 : // Set the status bar similarly for mouseover and focus
3160 : case eMouseOver:
3161 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
3162 : MOZ_FALLTHROUGH;
3163 : case eFocus: {
3164 0 : InternalFocusEvent* focusEvent = aVisitor.mEvent->AsFocusEvent();
3165 0 : if (!focusEvent || !focusEvent->mIsRefocus) {
3166 0 : nsAutoString target;
3167 0 : GetLinkTarget(target);
3168 0 : nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
3169 0 : false, true, true);
3170 : // Make sure any ancestor links don't also TriggerLink
3171 0 : aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
3172 : }
3173 0 : break;
3174 : }
3175 : case eMouseOut:
3176 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
3177 : MOZ_FALLTHROUGH;
3178 : case eBlur:
3179 0 : rv = LeaveLink(aVisitor.mPresContext);
3180 0 : if (NS_SUCCEEDED(rv)) {
3181 0 : aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
3182 : }
3183 0 : break;
3184 :
3185 : default:
3186 : // switch not in sync with the optimization switch earlier in this function
3187 0 : NS_NOTREACHED("switch statements not in sync");
3188 0 : return NS_ERROR_UNEXPECTED;
3189 : }
3190 :
3191 0 : return rv;
3192 : }
3193 :
3194 : nsresult
3195 0 : Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor)
3196 : {
3197 : // Optimisation: return early if this event doesn't interest us.
3198 : // IMPORTANT: this switch and the switch below it must be kept in sync!
3199 0 : switch (aVisitor.mEvent->mMessage) {
3200 : case eMouseDown:
3201 : case eMouseClick:
3202 : case eLegacyDOMActivate:
3203 : case eKeyPress:
3204 0 : break;
3205 : default:
3206 0 : return NS_OK;
3207 : }
3208 :
3209 : // Make sure we meet the preconditions before continuing
3210 0 : nsCOMPtr<nsIURI> absURI;
3211 0 : if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
3212 0 : return NS_OK;
3213 : }
3214 :
3215 0 : nsresult rv = NS_OK;
3216 :
3217 0 : switch (aVisitor.mEvent->mMessage) {
3218 : case eMouseDown:
3219 : {
3220 0 : if (aVisitor.mEvent->AsMouseEvent()->button ==
3221 : WidgetMouseEvent::eLeftButton) {
3222 : // don't make the link grab the focus if there is no link handler
3223 0 : nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler();
3224 0 : nsIDocument *document = GetComposedDoc();
3225 0 : if (handler && document) {
3226 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
3227 0 : if (fm) {
3228 0 : aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
3229 0 : nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
3230 0 : fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE |
3231 0 : nsIFocusManager::FLAG_NOSCROLL);
3232 : }
3233 :
3234 0 : EventStateManager::SetActiveManager(
3235 0 : aVisitor.mPresContext->EventStateManager(), this);
3236 :
3237 : // OK, we're pretty sure we're going to load, so warm up a speculative
3238 : // connection to be sure we have one ready when we open the channel.
3239 : nsCOMPtr<nsISpeculativeConnect> sc =
3240 0 : do_QueryInterface(nsContentUtils::GetIOService());
3241 0 : nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(handler);
3242 0 : sc->SpeculativeConnect2(absURI, NodePrincipal(), ir);
3243 : }
3244 : }
3245 : }
3246 0 : break;
3247 :
3248 : case eMouseClick: {
3249 0 : WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
3250 0 : if (mouseEvent->IsLeftClickEvent()) {
3251 0 : if (mouseEvent->IsControl() || mouseEvent->IsMeta() ||
3252 0 : mouseEvent->IsAlt() ||mouseEvent->IsShift()) {
3253 0 : break;
3254 : }
3255 :
3256 : // The default action is simply to dispatch DOMActivate
3257 0 : nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
3258 0 : if (shell) {
3259 : // single-click
3260 0 : nsEventStatus status = nsEventStatus_eIgnore;
3261 : // DOMActive event should be trusted since the activation is actually
3262 : // occurred even if the cause is an untrusted click event.
3263 0 : InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent);
3264 0 : actEvent.mDetail = 1;
3265 :
3266 0 : rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
3267 0 : if (NS_SUCCEEDED(rv)) {
3268 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
3269 : }
3270 : }
3271 : }
3272 0 : break;
3273 : }
3274 : case eLegacyDOMActivate:
3275 : {
3276 0 : if (aVisitor.mEvent->mOriginalTarget == this) {
3277 0 : nsAutoString target;
3278 0 : GetLinkTarget(target);
3279 0 : const InternalUIEvent* activeEvent = aVisitor.mEvent->AsUIEvent();
3280 0 : MOZ_ASSERT(activeEvent);
3281 0 : nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
3282 0 : true, true, activeEvent->IsTrustable());
3283 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
3284 : }
3285 : }
3286 0 : break;
3287 :
3288 : case eKeyPress:
3289 : {
3290 0 : WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
3291 0 : if (keyEvent && keyEvent->mKeyCode == NS_VK_RETURN) {
3292 0 : nsEventStatus status = nsEventStatus_eIgnore;
3293 0 : rv = DispatchClickEvent(aVisitor.mPresContext, keyEvent, this,
3294 0 : false, nullptr, &status);
3295 0 : if (NS_SUCCEEDED(rv)) {
3296 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
3297 : }
3298 : }
3299 : }
3300 0 : break;
3301 :
3302 : default:
3303 : // switch not in sync with the optimization switch earlier in this function
3304 0 : NS_NOTREACHED("switch statements not in sync");
3305 0 : return NS_ERROR_UNEXPECTED;
3306 : }
3307 :
3308 0 : return rv;
3309 : }
3310 :
3311 : void
3312 0 : Element::GetLinkTarget(nsAString& aTarget)
3313 : {
3314 0 : aTarget.Truncate();
3315 0 : }
3316 :
3317 : static void
3318 0 : nsDOMTokenListPropertyDestructor(void *aObject, nsIAtom *aProperty,
3319 : void *aPropertyValue, void *aData)
3320 : {
3321 : nsDOMTokenList* list =
3322 0 : static_cast<nsDOMTokenList*>(aPropertyValue);
3323 0 : NS_RELEASE(list);
3324 0 : }
3325 :
3326 : static nsIAtom** sPropertiesToTraverseAndUnlink[] =
3327 : {
3328 : &nsGkAtoms::sandbox,
3329 : &nsGkAtoms::sizes,
3330 : &nsGkAtoms::dirAutoSetBy,
3331 : nullptr
3332 : };
3333 :
3334 : // static
3335 : nsIAtom***
3336 0 : Element::HTMLSVGPropertiesToTraverseAndUnlink()
3337 : {
3338 0 : return sPropertiesToTraverseAndUnlink;
3339 : }
3340 :
3341 : nsDOMTokenList*
3342 0 : Element::GetTokenList(nsIAtom* aAtom,
3343 : const DOMTokenListSupportedTokenArray aSupportedTokens)
3344 : {
3345 : #ifdef DEBUG
3346 : nsIAtom*** props =
3347 0 : HTMLSVGPropertiesToTraverseAndUnlink();
3348 0 : bool found = false;
3349 0 : for (uint32_t i = 0; props[i]; ++i) {
3350 0 : if (*props[i] == aAtom) {
3351 0 : found = true;
3352 0 : break;
3353 : }
3354 : }
3355 0 : MOZ_ASSERT(found, "Trying to use an unknown tokenlist!");
3356 : #endif
3357 :
3358 0 : nsDOMTokenList* list = nullptr;
3359 0 : if (HasProperties()) {
3360 0 : list = static_cast<nsDOMTokenList*>(GetProperty(aAtom));
3361 : }
3362 0 : if (!list) {
3363 0 : list = new nsDOMTokenList(this, aAtom, aSupportedTokens);
3364 0 : NS_ADDREF(list);
3365 0 : SetProperty(aAtom, list, nsDOMTokenListPropertyDestructor);
3366 : }
3367 0 : return list;
3368 : }
3369 :
3370 : Element*
3371 0 : Element::Closest(const nsAString& aSelector, ErrorResult& aResult)
3372 : {
3373 0 : nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aResult);
3374 0 : if (!selectorList) {
3375 : // Either we failed (and aResult already has the exception), or this
3376 : // is a pseudo-element-only selector that matches nothing.
3377 0 : return nullptr;
3378 : }
3379 : TreeMatchContext matchingContext(false,
3380 : nsRuleWalker::eRelevantLinkUnvisited,
3381 : OwnerDoc(),
3382 0 : TreeMatchContext::eNeverMatchVisited);
3383 0 : matchingContext.SetHasSpecifiedScope();
3384 0 : matchingContext.AddScopeElement(this);
3385 0 : for (nsINode* node = this; node; node = node->GetParentNode()) {
3386 0 : if (node->IsElement() &&
3387 0 : nsCSSRuleProcessor::SelectorListMatches(node->AsElement(),
3388 : matchingContext,
3389 : selectorList)) {
3390 0 : return node->AsElement();
3391 : }
3392 : }
3393 0 : return nullptr;
3394 : }
3395 :
3396 : bool
3397 0 : Element::Matches(const nsAString& aSelector, ErrorResult& aError)
3398 : {
3399 0 : nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aError);
3400 0 : if (!selectorList) {
3401 : // Either we failed (and aError already has the exception), or this
3402 : // is a pseudo-element-only selector that matches nothing.
3403 0 : return false;
3404 : }
3405 :
3406 : TreeMatchContext matchingContext(false,
3407 : nsRuleWalker::eRelevantLinkUnvisited,
3408 : OwnerDoc(),
3409 0 : TreeMatchContext::eNeverMatchVisited);
3410 0 : matchingContext.SetHasSpecifiedScope();
3411 0 : matchingContext.AddScopeElement(this);
3412 : return nsCSSRuleProcessor::SelectorListMatches(this, matchingContext,
3413 0 : selectorList);
3414 : }
3415 :
3416 : static const nsAttrValue::EnumTable kCORSAttributeTable[] = {
3417 : // Order matters here
3418 : // See ParseCORSValue
3419 : { "anonymous", CORS_ANONYMOUS },
3420 : { "use-credentials", CORS_USE_CREDENTIALS },
3421 : { nullptr, 0 }
3422 : };
3423 :
3424 : /* static */ void
3425 0 : Element::ParseCORSValue(const nsAString& aValue,
3426 : nsAttrValue& aResult)
3427 : {
3428 : DebugOnly<bool> success =
3429 0 : aResult.ParseEnumValue(aValue, kCORSAttributeTable, false,
3430 : // default value is anonymous if aValue is
3431 : // not a value we understand
3432 0 : &kCORSAttributeTable[0]);
3433 0 : MOZ_ASSERT(success);
3434 0 : }
3435 :
3436 : /* static */ CORSMode
3437 4 : Element::StringToCORSMode(const nsAString& aValue)
3438 : {
3439 4 : if (aValue.IsVoid()) {
3440 4 : return CORS_NONE;
3441 : }
3442 :
3443 0 : nsAttrValue val;
3444 0 : Element::ParseCORSValue(aValue, val);
3445 0 : return CORSMode(val.GetEnumValue());
3446 : }
3447 :
3448 : /* static */ CORSMode
3449 8 : Element::AttrValueToCORSMode(const nsAttrValue* aValue)
3450 : {
3451 8 : if (!aValue) {
3452 8 : return CORS_NONE;
3453 : }
3454 :
3455 0 : return CORSMode(aValue->GetEnumValue());
3456 : }
3457 :
3458 : static const char*
3459 0 : GetFullScreenError(CallerType aCallerType)
3460 : {
3461 0 : if (!nsContentUtils::IsRequestFullScreenAllowed(aCallerType)) {
3462 0 : return "FullscreenDeniedNotInputDriven";
3463 : }
3464 :
3465 0 : return nullptr;
3466 : }
3467 :
3468 : void
3469 0 : Element::RequestFullscreen(CallerType aCallerType, ErrorResult& aError)
3470 : {
3471 : // Only grant full-screen requests if this is called from inside a trusted
3472 : // event handler (i.e. inside an event handler for a user initiated event).
3473 : // This stops the full-screen from being abused similar to the popups of old,
3474 : // and it also makes it harder for bad guys' script to go full-screen and
3475 : // spoof the browser chrome/window and phish logins etc.
3476 : // Note that requests for fullscreen inside a web app's origin are exempt
3477 : // from this restriction.
3478 0 : if (const char* error = GetFullScreenError(aCallerType)) {
3479 0 : OwnerDoc()->DispatchFullscreenError(error);
3480 0 : return;
3481 : }
3482 :
3483 0 : auto request = MakeUnique<FullscreenRequest>(this);
3484 0 : request->mIsCallerChrome = (aCallerType == CallerType::System);
3485 :
3486 0 : OwnerDoc()->AsyncRequestFullScreen(Move(request));
3487 : }
3488 :
3489 : void
3490 0 : Element::RequestPointerLock(CallerType aCallerType)
3491 : {
3492 0 : OwnerDoc()->RequestPointerLock(this, aCallerType);
3493 0 : }
3494 :
3495 : void
3496 0 : Element::GetGridFragments(nsTArray<RefPtr<Grid>>& aResult)
3497 : {
3498 : nsGridContainerFrame* frame =
3499 0 : nsGridContainerFrame::GetGridFrameWithComputedInfo(GetPrimaryFrame());
3500 :
3501 : // If we get a nsGridContainerFrame from the prior call,
3502 : // all the next-in-flow frames will also be nsGridContainerFrames.
3503 0 : while (frame) {
3504 0 : aResult.AppendElement(
3505 0 : new Grid(this, frame)
3506 0 : );
3507 0 : frame = static_cast<nsGridContainerFrame*>(frame->GetNextInFlow());
3508 : }
3509 0 : }
3510 :
3511 : already_AddRefed<DOMMatrixReadOnly>
3512 0 : Element::GetTransformToAncestor(Element& aAncestor)
3513 : {
3514 0 : nsIFrame* primaryFrame = GetPrimaryFrame();
3515 0 : nsIFrame* ancestorFrame = aAncestor.GetPrimaryFrame();
3516 :
3517 0 : Matrix4x4 transform;
3518 0 : if (primaryFrame) {
3519 : // If aAncestor is not actually an ancestor of this (including nullptr),
3520 : // then the call to GetTransformToAncestor will return the transform
3521 : // all the way up through the parent chain.
3522 0 : transform = nsLayoutUtils::GetTransformToAncestor(primaryFrame,
3523 : ancestorFrame, true);
3524 : }
3525 :
3526 0 : DOMMatrixReadOnly* matrix = new DOMMatrix(this, transform);
3527 0 : RefPtr<DOMMatrixReadOnly> result(matrix);
3528 0 : return result.forget();
3529 : }
3530 :
3531 : already_AddRefed<DOMMatrixReadOnly>
3532 0 : Element::GetTransformToParent()
3533 : {
3534 0 : nsIFrame* primaryFrame = GetPrimaryFrame();
3535 :
3536 0 : Matrix4x4 transform;
3537 0 : if (primaryFrame) {
3538 0 : nsIFrame* parentFrame = primaryFrame->GetParent();
3539 0 : transform = nsLayoutUtils::GetTransformToAncestor(primaryFrame,
3540 : parentFrame, true);
3541 : }
3542 :
3543 0 : DOMMatrixReadOnly* matrix = new DOMMatrix(this, transform);
3544 0 : RefPtr<DOMMatrixReadOnly> result(matrix);
3545 0 : return result.forget();
3546 : }
3547 :
3548 : already_AddRefed<DOMMatrixReadOnly>
3549 0 : Element::GetTransformToViewport()
3550 : {
3551 0 : nsIFrame* primaryFrame = GetPrimaryFrame();
3552 0 : Matrix4x4 transform;
3553 0 : if (primaryFrame) {
3554 0 : transform = nsLayoutUtils::GetTransformToAncestor(primaryFrame,
3555 0 : nsLayoutUtils::GetDisplayRootFrame(primaryFrame), true);
3556 : }
3557 :
3558 0 : DOMMatrixReadOnly* matrix = new DOMMatrix(this, transform);
3559 0 : RefPtr<DOMMatrixReadOnly> result(matrix);
3560 0 : return result.forget();
3561 : }
3562 :
3563 : already_AddRefed<Animation>
3564 0 : Element::Animate(JSContext* aContext,
3565 : JS::Handle<JSObject*> aKeyframes,
3566 : const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
3567 : ErrorResult& aError)
3568 : {
3569 0 : Nullable<ElementOrCSSPseudoElement> target;
3570 0 : target.SetValue().SetAsElement() = this;
3571 0 : return Animate(target, aContext, aKeyframes, aOptions, aError);
3572 : }
3573 :
3574 : /* static */ already_AddRefed<Animation>
3575 0 : Element::Animate(const Nullable<ElementOrCSSPseudoElement>& aTarget,
3576 : JSContext* aContext,
3577 : JS::Handle<JSObject*> aKeyframes,
3578 : const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
3579 : ErrorResult& aError)
3580 : {
3581 0 : MOZ_ASSERT(!aTarget.IsNull() &&
3582 : (aTarget.Value().IsElement() ||
3583 : aTarget.Value().IsCSSPseudoElement()),
3584 : "aTarget should be initialized");
3585 :
3586 0 : RefPtr<Element> referenceElement;
3587 0 : if (aTarget.Value().IsElement()) {
3588 0 : referenceElement = &aTarget.Value().GetAsElement();
3589 : } else {
3590 0 : referenceElement = aTarget.Value().GetAsCSSPseudoElement().ParentElement();
3591 : }
3592 :
3593 0 : nsCOMPtr<nsIGlobalObject> ownerGlobal = referenceElement->GetOwnerGlobal();
3594 0 : if (!ownerGlobal) {
3595 0 : aError.Throw(NS_ERROR_FAILURE);
3596 0 : return nullptr;
3597 : }
3598 0 : GlobalObject global(aContext, ownerGlobal->GetGlobalJSObject());
3599 0 : MOZ_ASSERT(!global.Failed());
3600 :
3601 : // Wrap the aKeyframes object for the cross-compartment case.
3602 0 : JS::Rooted<JSObject*> keyframes(aContext);
3603 0 : keyframes = aKeyframes;
3604 0 : Maybe<JSAutoCompartment> ac;
3605 0 : if (js::GetContextCompartment(aContext) !=
3606 0 : js::GetObjectCompartment(ownerGlobal->GetGlobalJSObject())) {
3607 0 : ac.emplace(aContext, ownerGlobal->GetGlobalJSObject());
3608 0 : if (!JS_WrapObject(aContext, &keyframes)) {
3609 0 : return nullptr;
3610 : }
3611 : }
3612 :
3613 : RefPtr<KeyframeEffect> effect =
3614 0 : KeyframeEffect::Constructor(global, aTarget, keyframes, aOptions, aError);
3615 0 : if (aError.Failed()) {
3616 0 : return nullptr;
3617 : }
3618 :
3619 0 : AnimationTimeline* timeline = referenceElement->OwnerDoc()->Timeline();
3620 : RefPtr<Animation> animation =
3621 0 : Animation::Constructor(global, effect,
3622 0 : Optional<AnimationTimeline*>(timeline), aError);
3623 0 : if (aError.Failed()) {
3624 0 : return nullptr;
3625 : }
3626 :
3627 0 : if (aOptions.IsKeyframeAnimationOptions()) {
3628 0 : animation->SetId(aOptions.GetAsKeyframeAnimationOptions().mId);
3629 : }
3630 :
3631 0 : animation->Play(aError, Animation::LimitBehavior::AutoRewind);
3632 0 : if (aError.Failed()) {
3633 0 : return nullptr;
3634 : }
3635 :
3636 0 : return animation.forget();
3637 : }
3638 :
3639 : void
3640 0 : Element::GetAnimations(const AnimationFilter& filter,
3641 : nsTArray<RefPtr<Animation>>& aAnimations)
3642 : {
3643 0 : nsIDocument* doc = GetComposedDoc();
3644 0 : if (doc) {
3645 0 : doc->FlushPendingNotifications(FlushType::Style);
3646 : }
3647 :
3648 0 : Element* elem = this;
3649 0 : CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
3650 : // For animations on generated-content elements, the animations are stored
3651 : // on the parent element.
3652 0 : if (IsGeneratedContentContainerForBefore()) {
3653 0 : elem = GetParentElement();
3654 0 : pseudoType = CSSPseudoElementType::before;
3655 0 : } else if (IsGeneratedContentContainerForAfter()) {
3656 0 : elem = GetParentElement();
3657 0 : pseudoType = CSSPseudoElementType::after;
3658 : }
3659 :
3660 0 : if (!elem) {
3661 0 : return;
3662 : }
3663 :
3664 0 : if (!filter.mSubtree ||
3665 0 : pseudoType == CSSPseudoElementType::before ||
3666 : pseudoType == CSSPseudoElementType::after) {
3667 0 : GetAnimationsUnsorted(elem, pseudoType, aAnimations);
3668 : } else {
3669 0 : for (nsIContent* node = this;
3670 0 : node;
3671 0 : node = node->GetNextNode(this)) {
3672 0 : if (!node->IsElement()) {
3673 0 : continue;
3674 : }
3675 0 : Element* element = node->AsElement();
3676 : Element::GetAnimationsUnsorted(element, CSSPseudoElementType::NotPseudo,
3677 0 : aAnimations);
3678 : Element::GetAnimationsUnsorted(element, CSSPseudoElementType::before,
3679 0 : aAnimations);
3680 : Element::GetAnimationsUnsorted(element, CSSPseudoElementType::after,
3681 0 : aAnimations);
3682 : }
3683 : }
3684 0 : aAnimations.Sort(AnimationPtrComparator<RefPtr<Animation>>());
3685 : }
3686 :
3687 : /* static */ void
3688 0 : Element::GetAnimationsUnsorted(Element* aElement,
3689 : CSSPseudoElementType aPseudoType,
3690 : nsTArray<RefPtr<Animation>>& aAnimations)
3691 : {
3692 0 : MOZ_ASSERT(aPseudoType == CSSPseudoElementType::NotPseudo ||
3693 : aPseudoType == CSSPseudoElementType::after ||
3694 : aPseudoType == CSSPseudoElementType::before,
3695 : "Unsupported pseudo type");
3696 0 : MOZ_ASSERT(aElement, "Null element");
3697 :
3698 0 : EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
3699 0 : if (!effects) {
3700 0 : return;
3701 : }
3702 :
3703 0 : for (KeyframeEffectReadOnly* effect : *effects) {
3704 0 : MOZ_ASSERT(effect && effect->GetAnimation(),
3705 : "Only effects associated with an animation should be "
3706 : "added to an element's effect set");
3707 0 : Animation* animation = effect->GetAnimation();
3708 :
3709 0 : MOZ_ASSERT(animation->IsRelevant(),
3710 : "Only relevant animations should be added to an element's "
3711 : "effect set");
3712 0 : aAnimations.AppendElement(animation);
3713 : }
3714 : }
3715 :
3716 : NS_IMETHODIMP
3717 0 : Element::GetInnerHTML(nsAString& aInnerHTML)
3718 : {
3719 0 : GetMarkup(false, aInnerHTML);
3720 0 : return NS_OK;
3721 : }
3722 :
3723 : void
3724 0 : Element::SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
3725 : {
3726 0 : SetInnerHTMLInternal(aInnerHTML, aError);
3727 0 : }
3728 :
3729 : void
3730 0 : Element::GetOuterHTML(nsAString& aOuterHTML)
3731 : {
3732 0 : GetMarkup(true, aOuterHTML);
3733 0 : }
3734 :
3735 : void
3736 0 : Element::SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError)
3737 : {
3738 0 : nsCOMPtr<nsINode> parent = GetParentNode();
3739 0 : if (!parent) {
3740 0 : return;
3741 : }
3742 :
3743 0 : if (parent->NodeType() == nsIDOMNode::DOCUMENT_NODE) {
3744 0 : aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
3745 0 : return;
3746 : }
3747 :
3748 0 : if (OwnerDoc()->IsHTMLDocument()) {
3749 : nsIAtom* localName;
3750 : int32_t namespaceID;
3751 0 : if (parent->IsElement()) {
3752 0 : localName = parent->NodeInfo()->NameAtom();
3753 0 : namespaceID = parent->NodeInfo()->NamespaceID();
3754 : } else {
3755 0 : NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
3756 : "How come the parent isn't a document, a fragment or an element?");
3757 0 : localName = nsGkAtoms::body;
3758 0 : namespaceID = kNameSpaceID_XHTML;
3759 : }
3760 : RefPtr<DocumentFragment> fragment =
3761 0 : new DocumentFragment(OwnerDoc()->NodeInfoManager());
3762 0 : nsContentUtils::ParseFragmentHTML(aOuterHTML,
3763 : fragment,
3764 : localName,
3765 : namespaceID,
3766 0 : OwnerDoc()->GetCompatibilityMode() ==
3767 : eCompatibility_NavQuirks,
3768 0 : true);
3769 0 : parent->ReplaceChild(*fragment, *this, aError);
3770 0 : return;
3771 : }
3772 :
3773 0 : nsCOMPtr<nsINode> context;
3774 0 : if (parent->IsElement()) {
3775 0 : context = parent;
3776 : } else {
3777 0 : NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
3778 : "How come the parent isn't a document, a fragment or an element?");
3779 : RefPtr<mozilla::dom::NodeInfo> info =
3780 0 : OwnerDoc()->NodeInfoManager()->GetNodeInfo(nsGkAtoms::body,
3781 : nullptr,
3782 : kNameSpaceID_XHTML,
3783 0 : nsIDOMNode::ELEMENT_NODE);
3784 0 : context = NS_NewHTMLBodyElement(info.forget(), FROM_PARSER_FRAGMENT);
3785 : }
3786 :
3787 0 : nsCOMPtr<nsIDOMDocumentFragment> df;
3788 0 : aError = nsContentUtils::CreateContextualFragment(context,
3789 : aOuterHTML,
3790 : true,
3791 0 : getter_AddRefs(df));
3792 0 : if (aError.Failed()) {
3793 0 : return;
3794 : }
3795 0 : nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
3796 0 : parent->ReplaceChild(*fragment, *this, aError);
3797 : }
3798 :
3799 : enum nsAdjacentPosition {
3800 : eBeforeBegin,
3801 : eAfterBegin,
3802 : eBeforeEnd,
3803 : eAfterEnd
3804 : };
3805 :
3806 : void
3807 0 : Element::InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
3808 : ErrorResult& aError)
3809 : {
3810 : nsAdjacentPosition position;
3811 0 : if (aPosition.LowerCaseEqualsLiteral("beforebegin")) {
3812 0 : position = eBeforeBegin;
3813 0 : } else if (aPosition.LowerCaseEqualsLiteral("afterbegin")) {
3814 0 : position = eAfterBegin;
3815 0 : } else if (aPosition.LowerCaseEqualsLiteral("beforeend")) {
3816 0 : position = eBeforeEnd;
3817 0 : } else if (aPosition.LowerCaseEqualsLiteral("afterend")) {
3818 0 : position = eAfterEnd;
3819 : } else {
3820 0 : aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
3821 0 : return;
3822 : }
3823 :
3824 0 : nsCOMPtr<nsIContent> destination;
3825 0 : if (position == eBeforeBegin || position == eAfterEnd) {
3826 0 : destination = GetParent();
3827 0 : if (!destination) {
3828 0 : aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
3829 0 : return;
3830 : }
3831 : } else {
3832 0 : destination = this;
3833 : }
3834 :
3835 0 : nsIDocument* doc = OwnerDoc();
3836 :
3837 : // Needed when insertAdjacentHTML is used in combination with contenteditable
3838 0 : mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
3839 0 : nsAutoScriptLoaderDisabler sld(doc);
3840 :
3841 : // Batch possible DOMSubtreeModified events.
3842 0 : mozAutoSubtreeModified subtree(doc, nullptr);
3843 :
3844 : // Parse directly into destination if possible
3845 0 : if (doc->IsHTMLDocument() && !OwnerDoc()->MayHaveDOMMutationObservers() &&
3846 0 : (position == eBeforeEnd ||
3847 0 : (position == eAfterEnd && !GetNextSibling()) ||
3848 0 : (position == eAfterBegin && !GetFirstChild()))) {
3849 0 : int32_t oldChildCount = destination->GetChildCount();
3850 0 : int32_t contextNs = destination->GetNameSpaceID();
3851 0 : nsIAtom* contextLocal = destination->NodeInfo()->NameAtom();
3852 0 : if (contextLocal == nsGkAtoms::html && contextNs == kNameSpaceID_XHTML) {
3853 : // For compat with IE6 through IE9. Willful violation of HTML5 as of
3854 : // 2011-04-06. CreateContextualFragment does the same already.
3855 : // Spec bug: http://www.w3.org/Bugs/Public/show_bug.cgi?id=12434
3856 0 : contextLocal = nsGkAtoms::body;
3857 : }
3858 0 : aError = nsContentUtils::ParseFragmentHTML(aText,
3859 : destination,
3860 : contextLocal,
3861 : contextNs,
3862 0 : doc->GetCompatibilityMode() ==
3863 : eCompatibility_NavQuirks,
3864 0 : true);
3865 : // HTML5 parser has notified, but not fired mutation events.
3866 0 : nsContentUtils::FireMutationEventsForDirectParsing(doc, destination,
3867 0 : oldChildCount);
3868 0 : return;
3869 : }
3870 :
3871 : // couldn't parse directly
3872 0 : nsCOMPtr<nsIDOMDocumentFragment> df;
3873 0 : aError = nsContentUtils::CreateContextualFragment(destination,
3874 : aText,
3875 : true,
3876 0 : getter_AddRefs(df));
3877 0 : if (aError.Failed()) {
3878 0 : return;
3879 : }
3880 :
3881 0 : nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
3882 :
3883 : // Suppress assertion about node removal mutation events that can't have
3884 : // listeners anyway, because no one has had the chance to register mutation
3885 : // listeners on the fragment that comes from the parser.
3886 0 : nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
3887 :
3888 0 : nsAutoMutationBatch mb(destination, true, false);
3889 0 : switch (position) {
3890 : case eBeforeBegin:
3891 0 : destination->InsertBefore(*fragment, this, aError);
3892 0 : break;
3893 : case eAfterBegin:
3894 0 : static_cast<nsINode*>(this)->InsertBefore(*fragment, GetFirstChild(),
3895 0 : aError);
3896 0 : break;
3897 : case eBeforeEnd:
3898 0 : static_cast<nsINode*>(this)->AppendChild(*fragment, aError);
3899 0 : break;
3900 : case eAfterEnd:
3901 0 : destination->InsertBefore(*fragment, GetNextSibling(), aError);
3902 0 : break;
3903 : }
3904 : }
3905 :
3906 : nsINode*
3907 0 : Element::InsertAdjacent(const nsAString& aWhere,
3908 : nsINode* aNode,
3909 : ErrorResult& aError)
3910 : {
3911 0 : if (aWhere.LowerCaseEqualsLiteral("beforebegin")) {
3912 0 : nsCOMPtr<nsINode> parent = GetParentNode();
3913 0 : if (!parent) {
3914 0 : return nullptr;
3915 : }
3916 0 : parent->InsertBefore(*aNode, this, aError);
3917 0 : } else if (aWhere.LowerCaseEqualsLiteral("afterbegin")) {
3918 0 : nsCOMPtr<nsINode> refNode = GetFirstChild();
3919 0 : static_cast<nsINode*>(this)->InsertBefore(*aNode, refNode, aError);
3920 0 : } else if (aWhere.LowerCaseEqualsLiteral("beforeend")) {
3921 0 : static_cast<nsINode*>(this)->AppendChild(*aNode, aError);
3922 0 : } else if (aWhere.LowerCaseEqualsLiteral("afterend")) {
3923 0 : nsCOMPtr<nsINode> parent = GetParentNode();
3924 0 : if (!parent) {
3925 0 : return nullptr;
3926 : }
3927 0 : nsCOMPtr<nsINode> refNode = GetNextSibling();
3928 0 : parent->InsertBefore(*aNode, refNode, aError);
3929 : } else {
3930 0 : aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
3931 0 : return nullptr;
3932 : }
3933 :
3934 0 : return aError.Failed() ? nullptr : aNode;
3935 : }
3936 :
3937 : Element*
3938 0 : Element::InsertAdjacentElement(const nsAString& aWhere,
3939 : Element& aElement,
3940 : ErrorResult& aError) {
3941 0 : nsINode* newNode = InsertAdjacent(aWhere, &aElement, aError);
3942 0 : MOZ_ASSERT(!newNode || newNode->IsElement());
3943 :
3944 0 : return newNode ? newNode->AsElement() : nullptr;
3945 : }
3946 :
3947 : void
3948 0 : Element::InsertAdjacentText(
3949 : const nsAString& aWhere, const nsAString& aData, ErrorResult& aError)
3950 : {
3951 0 : RefPtr<nsTextNode> textNode = OwnerDoc()->CreateTextNode(aData);
3952 0 : InsertAdjacent(aWhere, textNode, aError);
3953 0 : }
3954 :
3955 : TextEditor*
3956 0 : Element::GetTextEditorInternal()
3957 : {
3958 0 : nsCOMPtr<nsITextControlElement> textCtrl = do_QueryInterface(this);
3959 0 : return textCtrl ? textCtrl->GetTextEditor() : nullptr;
3960 : }
3961 :
3962 : nsresult
3963 0 : Element::SetBoolAttr(nsIAtom* aAttr, bool aValue)
3964 : {
3965 0 : if (aValue) {
3966 0 : return SetAttr(kNameSpaceID_None, aAttr, EmptyString(), true);
3967 : }
3968 :
3969 0 : return UnsetAttr(kNameSpaceID_None, aAttr, true);
3970 : }
3971 :
3972 : void
3973 0 : Element::GetEnumAttr(nsIAtom* aAttr,
3974 : const char* aDefault,
3975 : nsAString& aResult) const
3976 : {
3977 0 : GetEnumAttr(aAttr, aDefault, aDefault, aResult);
3978 0 : }
3979 :
3980 : void
3981 0 : Element::GetEnumAttr(nsIAtom* aAttr,
3982 : const char* aDefaultMissing,
3983 : const char* aDefaultInvalid,
3984 : nsAString& aResult) const
3985 : {
3986 0 : const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
3987 :
3988 0 : aResult.Truncate();
3989 :
3990 0 : if (!attrVal) {
3991 0 : if (aDefaultMissing) {
3992 0 : AppendASCIItoUTF16(nsDependentCString(aDefaultMissing), aResult);
3993 : } else {
3994 0 : SetDOMStringToNull(aResult);
3995 : }
3996 : } else {
3997 0 : if (attrVal->Type() == nsAttrValue::eEnum) {
3998 0 : attrVal->GetEnumString(aResult, true);
3999 0 : } else if (aDefaultInvalid) {
4000 0 : AppendASCIItoUTF16(nsDependentCString(aDefaultInvalid), aResult);
4001 : }
4002 : }
4003 0 : }
4004 :
4005 : void
4006 0 : Element::SetOrRemoveNullableStringAttr(nsIAtom* aName, const nsAString& aValue,
4007 : ErrorResult& aError)
4008 : {
4009 0 : if (DOMStringIsNull(aValue)) {
4010 0 : UnsetAttr(aName, aError);
4011 : } else {
4012 0 : SetAttr(aName, aValue, aError);
4013 : }
4014 0 : }
4015 :
4016 : Directionality
4017 0 : Element::GetComputedDirectionality() const
4018 : {
4019 0 : nsIFrame* frame = GetPrimaryFrame();
4020 0 : if (frame) {
4021 0 : return frame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR
4022 0 : ? eDir_LTR : eDir_RTL;
4023 : }
4024 :
4025 0 : return GetDirectionality();
4026 : }
4027 :
4028 : float
4029 0 : Element::FontSizeInflation()
4030 : {
4031 0 : nsIFrame* frame = GetPrimaryFrame();
4032 0 : if (!frame) {
4033 0 : return -1.0;
4034 : }
4035 :
4036 0 : if (nsLayoutUtils::FontSizeInflationEnabled(frame->PresContext())) {
4037 0 : return nsLayoutUtils::FontSizeInflationFor(frame);
4038 : }
4039 :
4040 0 : return 1.0;
4041 : }
4042 :
4043 : net::ReferrerPolicy
4044 4 : Element::GetReferrerPolicyAsEnum()
4045 : {
4046 4 : if (IsHTMLElement()) {
4047 4 : const nsAttrValue* referrerValue = GetParsedAttr(nsGkAtoms::referrerpolicy);
4048 4 : return ReferrerPolicyFromAttr(referrerValue);
4049 : }
4050 0 : return net::RP_Unset;
4051 : }
4052 :
4053 : net::ReferrerPolicy
4054 4 : Element::ReferrerPolicyFromAttr(const nsAttrValue* aValue)
4055 : {
4056 4 : if (aValue && aValue->Type() == nsAttrValue::eEnum) {
4057 0 : return net::ReferrerPolicy(aValue->GetEnumValue());
4058 : }
4059 4 : return net::RP_Unset;
4060 : }
4061 :
4062 : already_AddRefed<nsDOMStringMap>
4063 0 : Element::Dataset()
4064 : {
4065 0 : nsDOMSlots *slots = DOMSlots();
4066 :
4067 0 : if (!slots->mDataset) {
4068 : // mDataset is a weak reference so assignment will not AddRef.
4069 : // AddRef is called before returning the pointer.
4070 0 : slots->mDataset = new nsDOMStringMap(this);
4071 : }
4072 :
4073 0 : RefPtr<nsDOMStringMap> ret = slots->mDataset;
4074 0 : return ret.forget();
4075 : }
4076 :
4077 : void
4078 0 : Element::ClearDataset()
4079 : {
4080 0 : nsDOMSlots *slots = GetExistingDOMSlots();
4081 :
4082 0 : MOZ_ASSERT(slots && slots->mDataset,
4083 : "Slots should exist and dataset should not be null.");
4084 0 : slots->mDataset = nullptr;
4085 0 : }
4086 :
4087 : nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>*
4088 0 : Element::RegisteredIntersectionObservers()
4089 : {
4090 0 : nsDOMSlots* slots = DOMSlots();
4091 0 : return &slots->mRegisteredIntersectionObservers;
4092 : }
4093 :
4094 : enum nsPreviousIntersectionThreshold {
4095 : eUninitialized = -2,
4096 : eNonIntersecting = -1
4097 : };
4098 :
4099 : void
4100 0 : Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
4101 : {
4102 0 : RegisteredIntersectionObservers()->LookupForAdd(aObserver).OrInsert([]() {
4103 : // Value can be:
4104 : // -2: Makes sure next calculated threshold always differs, leading to a
4105 : // notification task being scheduled.
4106 : // -1: Non-intersecting.
4107 : // >= 0: Intersecting, valid index of aObserver->mThresholds.
4108 : return eUninitialized;
4109 0 : });
4110 0 : }
4111 :
4112 : void
4113 0 : Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
4114 : {
4115 0 : RegisteredIntersectionObservers()->Remove(aObserver);
4116 0 : }
4117 :
4118 : bool
4119 0 : Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
4120 : {
4121 0 : bool updated = false;
4122 0 : if (auto entry = RegisteredIntersectionObservers()->Lookup(aObserver)) {
4123 0 : updated = entry.Data() != aThreshold;
4124 0 : entry.Data() = aThreshold;
4125 : }
4126 0 : return updated;
4127 : }
4128 :
4129 : void
4130 0 : Element::ClearServoData() {
4131 : #ifdef MOZ_STYLO
4132 : Servo_Element_ClearData(this);
4133 : #else
4134 0 : MOZ_CRASH("Accessing servo node data in non-stylo build");
4135 : #endif
4136 : }
4137 :
4138 : void
4139 0 : Element::SetCustomElementData(CustomElementData* aData)
4140 : {
4141 0 : nsDOMSlots *slots = DOMSlots();
4142 0 : MOZ_ASSERT(!slots->mCustomElementData, "Custom element data may not be changed once set.");
4143 0 : slots->mCustomElementData = aData;
4144 0 : }
|