content/base/src/Element.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=79: */
     3 /* 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/. */
     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  */
    13 #include "mozilla/dom/ElementInlines.h"
    15 #include "mozilla/DebugOnly.h"
    16 #include "mozilla/dom/Attr.h"
    17 #include "nsDOMAttributeMap.h"
    18 #include "nsIAtom.h"
    19 #include "nsIContentInlines.h"
    20 #include "nsINodeInfo.h"
    21 #include "nsIDocumentInlines.h"
    22 #include "nsIDOMNodeList.h"
    23 #include "nsIDOMDocument.h"
    24 #include "nsIContentIterator.h"
    25 #include "nsFocusManager.h"
    26 #include "nsILinkHandler.h"
    27 #include "nsIScriptGlobalObject.h"
    28 #include "nsIURL.h"
    29 #include "nsNetUtil.h"
    30 #include "nsIFrame.h"
    31 #include "nsIAnonymousContentCreator.h"
    32 #include "nsIPresShell.h"
    33 #include "nsPresContext.h"
    34 #include "nsStyleConsts.h"
    35 #include "nsString.h"
    36 #include "nsUnicharUtils.h"
    37 #include "nsIDOMEvent.h"
    38 #include "nsDOMCID.h"
    39 #include "nsIServiceManager.h"
    40 #include "nsIDOMCSSStyleDeclaration.h"
    41 #include "nsDOMCSSAttrDeclaration.h"
    42 #include "nsNameSpaceManager.h"
    43 #include "nsContentList.h"
    44 #include "nsDOMTokenList.h"
    45 #include "nsXBLPrototypeBinding.h"
    46 #include "nsError.h"
    47 #include "nsDOMString.h"
    48 #include "nsIScriptSecurityManager.h"
    49 #include "nsIDOMMutationEvent.h"
    50 #include "mozilla/AsyncEventDispatcher.h"
    51 #include "mozilla/ContentEvents.h"
    52 #include "mozilla/EventDispatcher.h"
    53 #include "mozilla/EventListenerManager.h"
    54 #include "mozilla/EventStateManager.h"
    55 #include "mozilla/EventStates.h"
    56 #include "mozilla/InternalMutationEvent.h"
    57 #include "mozilla/MouseEvents.h"
    58 #include "mozilla/TextEvents.h"
    59 #include "nsNodeUtils.h"
    60 #include "mozilla/dom/DirectionalityUtils.h"
    61 #include "nsDocument.h"
    62 #include "nsAttrValueOrString.h"
    63 #include "nsAttrValueInlines.h"
    64 #ifdef MOZ_XUL
    65 #include "nsXULElement.h"
    66 #endif /* MOZ_XUL */
    67 #include "nsFrameManager.h"
    68 #include "nsFrameSelection.h"
    69 #ifdef DEBUG
    70 #include "nsRange.h"
    71 #endif
    73 #include "nsBindingManager.h"
    74 #include "nsXBLBinding.h"
    75 #include "nsPIDOMWindow.h"
    76 #include "nsPIBoxObject.h"
    77 #include "mozilla/dom/DOMRect.h"
    78 #include "nsSVGUtils.h"
    79 #include "nsLayoutUtils.h"
    80 #include "nsGkAtoms.h"
    81 #include "nsContentUtils.h"
    82 #include "ChildIterator.h"
    84 #include "nsIDOMEventListener.h"
    85 #include "nsIWebNavigation.h"
    86 #include "nsIBaseWindow.h"
    87 #include "nsIWidget.h"
    89 #include "nsNodeInfoManager.h"
    90 #include "nsICategoryManager.h"
    91 #include "nsIDOMDocumentType.h"
    92 #include "nsIDOMUserDataHandler.h"
    93 #include "nsGenericHTMLElement.h"
    94 #include "nsIEditor.h"
    95 #include "nsIEditorIMESupport.h"
    96 #include "nsContentCreatorFunctions.h"
    97 #include "nsIControllers.h"
    98 #include "nsView.h"
    99 #include "nsViewManager.h"
   100 #include "nsIScrollableFrame.h"
   101 #include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */
   102 #include "nsCSSRuleProcessor.h"
   103 #include "nsRuleProcessorData.h"
   104 #include "nsTextNode.h"
   106 #ifdef MOZ_XUL
   107 #include "nsIXULDocument.h"
   108 #endif /* MOZ_XUL */
   110 #include "nsCycleCollectionParticipant.h"
   111 #include "nsCCUncollectableMarker.h"
   113 #include "mozAutoDocUpdate.h"
   115 #include "nsCSSParser.h"
   116 #include "prprf.h"
   117 #include "nsDOMMutationObserver.h"
   118 #include "nsSVGFeatures.h"
   119 #include "nsWrapperCacheInlines.h"
   120 #include "xpcpublic.h"
   121 #include "nsIScriptError.h"
   122 #include "mozilla/Telemetry.h"
   124 #include "mozilla/CORSMode.h"
   125 #include "mozilla/dom/ShadowRoot.h"
   127 #include "nsStyledElement.h"
   128 #include "nsXBLService.h"
   129 #include "nsITextControlElement.h"
   130 #include "nsITextControlFrame.h"
   131 #include "nsISupportsImpl.h"
   132 #include "mozilla/dom/DocumentFragment.h"
   133 #include "mozilla/IntegerPrintfMacros.h"
   135 using namespace mozilla;
   136 using namespace mozilla::dom;
   138 NS_IMETHODIMP
   139 Element::QueryInterface(REFNSIID aIID, void** aInstancePtr)
   140 {
   141   NS_ASSERTION(aInstancePtr,
   142                "QueryInterface requires a non-NULL destination!");
   143   nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr);
   144   if (NS_SUCCEEDED(rv)) {
   145     return NS_OK;
   146   }
   148   // Give the binding manager a chance to get an interface for this element.
   149   return OwnerDoc()->BindingManager()->GetBindingImplementation(this, aIID,
   150                                                                 aInstancePtr);
   151 }
   153 EventStates
   154 Element::IntrinsicState() const
   155 {
   156   return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE :
   157                         NS_EVENT_STATE_MOZ_READONLY;
   158 }
   160 void
   161 Element::NotifyStateChange(EventStates aStates)
   162 {
   163   nsIDocument* doc = GetCurrentDoc();
   164   if (doc) {
   165     nsAutoScriptBlocker scriptBlocker;
   166     doc->ContentStateChanged(this, aStates);
   167   }
   168 }
   170 void
   171 Element::UpdateLinkState(EventStates aState)
   172 {
   173   NS_ABORT_IF_FALSE(!aState.HasAtLeastOneOfStates(~(NS_EVENT_STATE_VISITED |
   174                                                     NS_EVENT_STATE_UNVISITED)),
   175                     "Unexpected link state bits");
   176   mState =
   177     (mState & ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) |
   178     aState;
   179 }
   181 void
   182 Element::UpdateState(bool aNotify)
   183 {
   184   EventStates oldState = mState;
   185   mState = IntrinsicState() | (oldState & ESM_MANAGED_STATES);
   186   if (aNotify) {
   187     EventStates changedStates = oldState ^ mState;
   188     if (!changedStates.IsEmpty()) {
   189       nsIDocument* doc = GetCurrentDoc();
   190       if (doc) {
   191         nsAutoScriptBlocker scriptBlocker;
   192         doc->ContentStateChanged(this, changedStates);
   193       }
   194     }
   195   }
   196 }
   198 void
   199 nsIContent::UpdateEditableState(bool aNotify)
   200 {
   201   // Guaranteed to be non-element content
   202   NS_ASSERTION(!IsElement(), "What happened here?");
   203   nsIContent *parent = GetParent();
   205   // Skip over unknown native anonymous content to avoid setting a flag we
   206   // can't clear later
   207   bool isUnknownNativeAnon = false;
   208   if (IsInNativeAnonymousSubtree()) {
   209     isUnknownNativeAnon = true;
   210     nsCOMPtr<nsIContent> root = this;
   211     while (root && !root->IsRootOfNativeAnonymousSubtree()) {
   212       root = root->GetParent();
   213     }
   214     // root should always be true here, but isn't -- bug 999416
   215     if (root) {
   216       nsIFrame* rootFrame = root->GetPrimaryFrame();
   217       if (rootFrame) {
   218         nsIFrame* parentFrame = rootFrame->GetParent();
   219         nsITextControlFrame* textCtrl = do_QueryFrame(parentFrame);
   220         isUnknownNativeAnon = !textCtrl;
   221       }
   222     }
   223   }
   225   SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE) &&
   226                   !isUnknownNativeAnon);
   227 }
   229 void
   230 Element::UpdateEditableState(bool aNotify)
   231 {
   232   nsIContent *parent = GetParent();
   234   SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
   235   if (aNotify) {
   236     UpdateState(aNotify);
   237   } else {
   238     // Avoid calling UpdateState in this very common case, because
   239     // this gets called for pretty much every single element on
   240     // insertion into the document and UpdateState can be slow for
   241     // some kinds of elements even when not notifying.
   242     if (IsEditable()) {
   243       RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
   244       AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
   245     } else {
   246       RemoveStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
   247       AddStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
   248     }
   249   }
   250 }
   252 EventStates
   253 Element::StyleStateFromLocks() const
   254 {
   255   EventStates locks = LockedStyleStates();
   256   EventStates state = mState | locks;
   258   if (locks.HasState(NS_EVENT_STATE_VISITED)) {
   259     return state & ~NS_EVENT_STATE_UNVISITED;
   260   }
   261   if (locks.HasState(NS_EVENT_STATE_UNVISITED)) {
   262     return state & ~NS_EVENT_STATE_VISITED;
   263   }
   264   return state;
   265 }
   267 EventStates
   268 Element::LockedStyleStates() const
   269 {
   270   EventStates* locks =
   271     static_cast<EventStates*>(GetProperty(nsGkAtoms::lockedStyleStates));
   272   if (locks) {
   273     return *locks;
   274   }
   275   return EventStates();
   276 }
   278 void
   279 Element::NotifyStyleStateChange(EventStates aStates)
   280 {
   281   nsIDocument* doc = GetCurrentDoc();
   282   if (doc) {
   283     nsIPresShell *presShell = doc->GetShell();
   284     if (presShell) {
   285       nsAutoScriptBlocker scriptBlocker;
   286       presShell->ContentStateChanged(doc, this, aStates);
   287     }
   288   }
   289 }
   291 void
   292 Element::LockStyleStates(EventStates aStates)
   293 {
   294   EventStates* locks = new EventStates(LockedStyleStates());
   296   *locks |= aStates;
   298   if (aStates.HasState(NS_EVENT_STATE_VISITED)) {
   299     *locks &= ~NS_EVENT_STATE_UNVISITED;
   300   }
   301   if (aStates.HasState(NS_EVENT_STATE_UNVISITED)) {
   302     *locks &= ~NS_EVENT_STATE_VISITED;
   303   }
   305   SetProperty(nsGkAtoms::lockedStyleStates, locks,
   306               nsINode::DeleteProperty<EventStates>);
   307   SetHasLockedStyleStates();
   309   NotifyStyleStateChange(aStates);
   310 }
   312 void
   313 Element::UnlockStyleStates(EventStates aStates)
   314 {
   315   EventStates* locks = new EventStates(LockedStyleStates());
   317   *locks &= ~aStates;
   319   if (locks->IsEmpty()) {
   320     DeleteProperty(nsGkAtoms::lockedStyleStates);
   321     ClearHasLockedStyleStates();
   322     delete locks;
   323   }
   324   else {
   325     SetProperty(nsGkAtoms::lockedStyleStates, locks,
   326                 nsINode::DeleteProperty<EventStates>);
   327   }
   329   NotifyStyleStateChange(aStates);
   330 }
   332 void
   333 Element::ClearStyleStateLocks()
   334 {
   335   EventStates locks = LockedStyleStates();
   337   DeleteProperty(nsGkAtoms::lockedStyleStates);
   338   ClearHasLockedStyleStates();
   340   NotifyStyleStateChange(locks);
   341 }
   343 bool
   344 Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
   345 {
   346   // If we have a frame the frame has already loaded the binding.  And
   347   // otherwise, don't do anything else here unless we're dealing with
   348   // XUL or an HTML element that may have a plugin-related overlay
   349   // (i.e. object, embed, or applet).
   350   bool isXULorPluginElement = (IsXUL() ||
   351                                IsHTML(nsGkAtoms::object) ||
   352                                IsHTML(nsGkAtoms::embed) ||
   353                                IsHTML(nsGkAtoms::applet));
   354   nsIPresShell *shell = aDocument->GetShell();
   355   if (!shell || GetPrimaryFrame() || !isXULorPluginElement) {
   356     *aResult = nullptr;
   358     return true;
   359   }
   361   // Get the computed -moz-binding directly from the style context
   362   nsPresContext *pctx = shell->GetPresContext();
   363   NS_ENSURE_TRUE(pctx, false);
   365   nsRefPtr<nsStyleContext> sc = pctx->StyleSet()->ResolveStyleFor(this,
   366                                                                   nullptr);
   367   NS_ENSURE_TRUE(sc, false);
   369   *aResult = sc->StyleDisplay()->mBinding;
   371   return true;
   372 }
   374 JSObject*
   375 Element::WrapObject(JSContext *aCx)
   376 {
   377   JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx));
   378   if (!obj) {
   379     return nullptr;
   380   }
   382   // Custom element prototype swizzling.
   383   CustomElementData* data = GetCustomElementData();
   384   if (obj && data) {
   385     // If this is a registered custom element then fix the prototype.
   386     JSAutoCompartment ac(aCx, obj);
   387     nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
   388     JS::Rooted<JSObject*> prototype(aCx);
   389     document->GetCustomPrototype(NodeInfo()->NamespaceID(), data->mType, &prototype);
   390     if (prototype) {
   391       if (!JS_WrapObject(aCx, &prototype) || !JS_SetPrototype(aCx, obj, prototype)) {
   392         dom::Throw(aCx, NS_ERROR_FAILURE);
   393         return nullptr;
   394       }
   395     }
   396   }
   398   nsIDocument* doc;
   399   if (HasFlag(NODE_FORCE_XBL_BINDINGS)) {
   400     doc = OwnerDoc();
   401   }
   402   else {
   403     doc = GetCurrentDoc();
   404   }
   406   if (!doc) {
   407     // There's no baseclass that cares about this call so we just
   408     // return here.
   409     return obj;
   410   }
   412   // We must ensure that the XBL Binding is installed before we hand
   413   // back this object.
   415   if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) && GetXBLBinding()) {
   416     // There's already a binding for this element so nothing left to
   417     // be done here.
   419     // In theory we could call ExecuteAttachedHandler here when it's safe to
   420     // run script if we also removed the binding from the PAQ queue, but that
   421     // seems like a scary change that would mosly just add more
   422     // inconsistencies.
   423     return obj;
   424   }
   426   // Make sure the style context goes away _before_ we load the binding
   427   // since that can destroy the relevant presshell.
   428   mozilla::css::URLValue *bindingURL;
   429   bool ok = GetBindingURL(doc, &bindingURL);
   430   if (!ok) {
   431     dom::Throw(aCx, NS_ERROR_FAILURE);
   432     return nullptr;
   433   }
   435   if (!bindingURL) {
   436     // No binding, nothing left to do here.
   437     return obj;
   438   }
   440   nsCOMPtr<nsIURI> uri = bindingURL->GetURI();
   441   nsCOMPtr<nsIPrincipal> principal = bindingURL->mOriginPrincipal;
   443   // We have a binding that must be installed.
   444   bool dummy;
   446   nsXBLService* xblService = nsXBLService::GetInstance();
   447   if (!xblService) {
   448     dom::Throw(aCx, NS_ERROR_NOT_AVAILABLE);
   449     return nullptr;
   450   }
   452   {
   453     // Make a scope so that ~nsRefPtr can GC before returning obj.
   454     nsRefPtr<nsXBLBinding> binding;
   455     xblService->LoadBindings(this, uri, principal, getter_AddRefs(binding), &dummy);
   457     if (binding) {
   458       if (nsContentUtils::IsSafeToRunScript()) {
   459         binding->ExecuteAttachedHandler();
   460       }
   461       else {
   462         nsContentUtils::AddScriptRunner(
   463           NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
   464       }
   465     }
   466   }
   468   return obj;
   469 }
   471 nsDOMTokenList*
   472 Element::GetClassList()
   473 {
   474   Element::nsDOMSlots *slots = DOMSlots();
   476   if (!slots->mClassList) {
   477     nsIAtom* classAttr = GetClassAttributeName();
   478     if (classAttr) {
   479       slots->mClassList = new nsDOMTokenList(this, classAttr);
   480     }
   481   }
   483   return slots->mClassList;
   484 }
   486 void
   487 Element::GetClassList(nsISupports** aClassList)
   488 {
   489   NS_IF_ADDREF(*aClassList = GetClassList());
   490 }
   492 already_AddRefed<nsIHTMLCollection>
   493 Element::GetElementsByTagName(const nsAString& aLocalName)
   494 {
   495   return NS_GetContentList(this, kNameSpaceID_Unknown, aLocalName);
   496 }
   498 void
   499 Element::GetElementsByTagName(const nsAString& aLocalName,
   500                               nsIDOMHTMLCollection** aResult)
   501 {
   502   *aResult = GetElementsByTagName(aLocalName).take();
   503 }
   505 nsIFrame*
   506 Element::GetStyledFrame()
   507 {
   508   nsIFrame *frame = GetPrimaryFrame(Flush_Layout);
   509   return frame ? nsLayoutUtils::GetStyleFrame(frame) : nullptr;
   510 }
   512 nsIScrollableFrame*
   513 Element::GetScrollFrame(nsIFrame **aStyledFrame, bool aFlushLayout)
   514 {
   515   // it isn't clear what to return for SVG nodes, so just return nothing
   516   if (IsSVG()) {
   517     if (aStyledFrame) {
   518       *aStyledFrame = nullptr;
   519     }
   520     return nullptr;
   521   }
   523   // Inline version of GetStyledFrame to use Flush_None if needed.
   524   nsIFrame* frame = GetPrimaryFrame(aFlushLayout ? Flush_Layout : Flush_None);
   525   if (frame) {
   526     frame = nsLayoutUtils::GetStyleFrame(frame);
   527   }
   529   if (aStyledFrame) {
   530     *aStyledFrame = frame;
   531   }
   532   if (!frame) {
   533     return nullptr;
   534   }
   536   // menu frames implement GetScrollTargetFrame but we don't want
   537   // to use it here.  Similar for comboboxes.
   538   nsIAtom* type = frame->GetType();
   539   if (type != nsGkAtoms::menuFrame && type != nsGkAtoms::comboboxControlFrame) {
   540     nsIScrollableFrame *scrollFrame = frame->GetScrollTargetFrame();
   541     if (scrollFrame)
   542       return scrollFrame;
   543   }
   545   nsIDocument* doc = OwnerDoc();
   546   bool quirksMode = doc->GetCompatibilityMode() == eCompatibility_NavQuirks;
   547   Element* elementWithRootScrollInfo =
   548     quirksMode ? doc->GetBodyElement() : doc->GetRootElement();
   549   if (this == elementWithRootScrollInfo) {
   550     // In quirks mode, the scroll info for the body element should map to the
   551     // root scrollable frame.
   552     // In strict mode, the scroll info for the root element should map to the
   553     // the root scrollable frame.
   554     return frame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
   555   }
   557   return nullptr;
   558 }
   560 void
   561 Element::ScrollIntoView(bool aTop)
   562 {
   563   nsIDocument *document = GetCurrentDoc();
   564   if (!document) {
   565     return;
   566   }
   568   // Get the presentation shell
   569   nsCOMPtr<nsIPresShell> presShell = document->GetShell();
   570   if (!presShell) {
   571     return;
   572   }
   574   int16_t vpercent = aTop ? nsIPresShell::SCROLL_TOP :
   575     nsIPresShell::SCROLL_BOTTOM;
   577   presShell->ScrollContentIntoView(this,
   578                                    nsIPresShell::ScrollAxis(
   579                                      vpercent,
   580                                      nsIPresShell::SCROLL_ALWAYS),
   581                                    nsIPresShell::ScrollAxis(),
   582                                    nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
   583 }
   585 bool
   586 Element::ScrollByNoFlush(int32_t aDx, int32_t aDy)
   587 {
   588   nsIScrollableFrame* sf = GetScrollFrame(nullptr, false);
   589   if (!sf) {
   590     return false;
   591   }
   593   nsWeakFrame weakRef(sf->GetScrolledFrame());
   595   CSSIntPoint before = sf->GetScrollPositionCSSPixels();
   596   sf->ScrollToCSSPixelsApproximate(CSSIntPoint(before.x + aDx, before.y + aDy));
   598   // The frame was destroyed, can't keep on scrolling.
   599   if (!weakRef.IsAlive()) {
   600     return false;
   601   }
   603   CSSIntPoint after = sf->GetScrollPositionCSSPixels();
   604   return (before != after);
   605 }
   607 static nsSize GetScrollRectSizeForOverflowVisibleFrame(nsIFrame* aFrame)
   608 {
   609   if (!aFrame) {
   610     return nsSize(0,0);
   611   }
   613   nsRect paddingRect = aFrame->GetPaddingRectRelativeToSelf();
   614   nsOverflowAreas overflowAreas(paddingRect, paddingRect);
   615   // Add the scrollable overflow areas of children (if any) to the paddingRect.
   616   // It's important to start with the paddingRect, otherwise if there are no
   617   // children the overflow rect will be 0,0,0,0 which will force the point 0,0
   618   // to be included in the final rect.
   619   nsLayoutUtils::UnionChildOverflow(aFrame, overflowAreas);
   620   // Make sure that an empty padding-rect's edges are included, by adding
   621   // the padding-rect in again with UnionEdges.
   622   nsRect overflowRect =
   623     overflowAreas.ScrollableOverflow().UnionEdges(paddingRect);
   624   return nsLayoutUtils::GetScrolledRect(aFrame,
   625       overflowRect, paddingRect.Size(),
   626       aFrame->StyleVisibility()->mDirection).Size();
   627 }
   629 int32_t
   630 Element::ScrollHeight()
   631 {
   632   if (IsSVG())
   633     return 0;
   635   nsIScrollableFrame* sf = GetScrollFrame();
   636   nscoord height;
   637   if (sf) {
   638     height = sf->GetScrollRange().height + sf->GetScrollPortRect().height;
   639   } else {
   640     height = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).height;
   641   }
   643   return nsPresContext::AppUnitsToIntCSSPixels(height);
   644 }
   646 int32_t
   647 Element::ScrollWidth()
   648 {
   649   if (IsSVG())
   650     return 0;
   652   nsIScrollableFrame* sf = GetScrollFrame();
   653   nscoord width;
   654   if (sf) {
   655     width = sf->GetScrollRange().width + sf->GetScrollPortRect().width;
   656   } else {
   657     width = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).width;
   658   }
   660   return nsPresContext::AppUnitsToIntCSSPixels(width);
   661 }
   663 nsRect
   664 Element::GetClientAreaRect()
   665 {
   666   nsIFrame* styledFrame;
   667   nsIScrollableFrame* sf = GetScrollFrame(&styledFrame);
   669   if (sf) {
   670     return sf->GetScrollPortRect();
   671   }
   673   if (styledFrame &&
   674       (styledFrame->StyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE ||
   675        styledFrame->IsFrameOfType(nsIFrame::eReplaced))) {
   676     // Special case code to make client area work even when there isn't
   677     // a scroll view, see bug 180552, bug 227567.
   678     return styledFrame->GetPaddingRect() - styledFrame->GetPositionIgnoringScrolling();
   679   }
   681   // SVG nodes reach here and just return 0
   682   return nsRect(0, 0, 0, 0);
   683 }
   685 already_AddRefed<DOMRect>
   686 Element::GetBoundingClientRect()
   687 {
   688   nsRefPtr<DOMRect> rect = new DOMRect(this);
   690   nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
   691   if (!frame) {
   692     // display:none, perhaps? Return the empty rect
   693     return rect.forget();
   694   }
   696   nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame,
   697           nsLayoutUtils::GetContainingBlockForClientRect(frame),
   698           nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
   699   rect->SetLayoutRect(r);
   700   return rect.forget();
   701 }
   703 already_AddRefed<DOMRectList>
   704 Element::GetClientRects()
   705 {
   706   nsRefPtr<DOMRectList> rectList = new DOMRectList(this);
   708   nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
   709   if (!frame) {
   710     // display:none, perhaps? Return an empty list
   711     return rectList.forget();
   712   }
   714   nsLayoutUtils::RectListBuilder builder(rectList);
   715   nsLayoutUtils::GetAllInFlowRects(frame,
   716           nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder,
   717           nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
   718   return rectList.forget();
   719 }
   722 //----------------------------------------------------------------------
   724 void
   725 Element::AddToIdTable(nsIAtom* aId)
   726 {
   727   NS_ASSERTION(HasID(), "Node doesn't have an ID?");
   728   if (HasFlag(NODE_IS_IN_SHADOW_TREE)) {
   729     ShadowRoot* containingShadow = GetContainingShadow();
   730     containingShadow->AddToIdTable(this, aId);
   731   } else {
   732     nsIDocument* doc = GetCurrentDoc();
   733     if (doc && (!IsInAnonymousSubtree() || doc->IsXUL())) {
   734       doc->AddToIdTable(this, aId);
   735     }
   736   }
   737 }
   739 void
   740 Element::RemoveFromIdTable()
   741 {
   742   if (HasID()) {
   743     RemoveFromIdTable(DoGetID());
   744   }
   745 }
   747 void
   748 Element::RemoveFromIdTable(nsIAtom* aId)
   749 {
   750   NS_ASSERTION(HasID(), "Node doesn't have an ID?");
   751   if (HasFlag(NODE_IS_IN_SHADOW_TREE)) {
   752     ShadowRoot* containingShadow = GetContainingShadow();
   753     // Check for containingShadow because it may have
   754     // been deleted during unlinking.
   755     if (containingShadow) {
   756       containingShadow->RemoveFromIdTable(this, aId);
   757     }
   758   } else {
   759     nsIDocument* doc = GetCurrentDoc();
   760     if (doc && (!IsInAnonymousSubtree() || doc->IsXUL())) {
   761       // id can be null during mutation events evilness. Also, XUL elements
   762       // loose their proto attributes during cc-unlink, so this can happen
   763       // during cc-unlink too.
   764       if (aId) {
   765         doc->RemoveFromIdTable(this, aId);
   766       }
   767     }
   768   }
   769 }
   771 already_AddRefed<ShadowRoot>
   772 Element::CreateShadowRoot(ErrorResult& aError)
   773 {
   774   nsAutoScriptBlocker scriptBlocker;
   776   nsCOMPtr<nsINodeInfo> nodeInfo;
   777   nodeInfo = mNodeInfo->NodeInfoManager()->GetNodeInfo(
   778     nsGkAtoms::documentFragmentNodeName, nullptr, kNameSpaceID_None,
   779     nsIDOMNode::DOCUMENT_FRAGMENT_NODE);
   781   nsRefPtr<nsXBLDocumentInfo> docInfo = new nsXBLDocumentInfo(OwnerDoc());
   783   nsXBLPrototypeBinding* protoBinding = new nsXBLPrototypeBinding();
   784   aError = protoBinding->Init(NS_LITERAL_CSTRING("shadowroot"),
   785                               docInfo, this, true);
   786   if (aError.Failed()) {
   787     delete protoBinding;
   788     return nullptr;
   789   }
   791   // Unlike for XBL, false is the default for inheriting style.
   792   protoBinding->SetInheritsStyle(false);
   794   // Calling SetPrototypeBinding takes ownership of protoBinding.
   795   docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
   797   nsRefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
   798                                                    protoBinding);
   800   // Replace the old ShadowRoot with the new one and let the old
   801   // ShadowRoot know about the younger ShadowRoot because the old
   802   // ShadowRoot is projected into the younger ShadowRoot's shadow
   803   // insertion point (if it exists).
   804   ShadowRoot* olderShadow = GetShadowRoot();
   805   SetShadowRoot(shadowRoot);
   806   if (olderShadow) {
   807     olderShadow->SetYoungerShadow(shadowRoot);
   808   }
   810   // xblBinding takes ownership of docInfo.
   811   nsRefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);
   812   shadowRoot->SetAssociatedBinding(xblBinding);
   813   xblBinding->SetBoundElement(this);
   815   SetXBLBinding(xblBinding);
   817   // Recreate the frame for the bound content because binding a ShadowRoot
   818   // changes how things are rendered.
   819   nsIDocument* doc = GetCurrentDoc();
   820   if (doc) {
   821     nsIPresShell *shell = doc->GetShell();
   822     if (shell) {
   823       shell->RecreateFramesFor(this);
   824     }
   825   }
   827   return shadowRoot.forget();
   828 }
   830 void
   831 Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
   832 {
   833   const nsAttrValue* val =
   834     mAttrsAndChildren.GetAttr(aName,
   835                               IsHTML() && IsInHTMLDocument() ?
   836                                 eIgnoreCase : eCaseMatters);
   837   if (val) {
   838     val->ToString(aReturn);
   839   } else {
   840     if (IsXUL()) {
   841       // XXX should be SetDOMStringToNull(aReturn);
   842       // See bug 232598
   843       // aReturn is already empty
   844     } else {
   845       aReturn.SetNull();
   846     }
   847   }
   848 }
   850 void
   851 Element::SetAttribute(const nsAString& aName,
   852                       const nsAString& aValue,
   853                       ErrorResult& aError)
   854 {
   855   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
   857   if (!name) {
   858     aError = nsContentUtils::CheckQName(aName, false);
   859     if (aError.Failed()) {
   860       return;
   861     }
   863     nsCOMPtr<nsIAtom> nameAtom;
   864     if (IsHTML() && IsInHTMLDocument()) {
   865       nsAutoString lower;
   866       nsresult rv = nsContentUtils::ASCIIToLower(aName, lower);
   867       if (NS_SUCCEEDED(rv)) {
   868         nameAtom = do_GetAtom(lower);
   869       }
   870     }
   871     else {
   872       nameAtom = do_GetAtom(aName);
   873     }
   874     if (!nameAtom) {
   875       aError.Throw(NS_ERROR_OUT_OF_MEMORY);
   876       return;
   877     }
   878     aError = SetAttr(kNameSpaceID_None, nameAtom, aValue, true);
   879     return;
   880   }
   882   aError = SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
   883                    aValue, true);
   884   return;
   885 }
   887 void
   888 Element::RemoveAttribute(const nsAString& aName, ErrorResult& aError)
   889 {
   890   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
   892   if (!name) {
   893     // If there is no canonical nsAttrName for this attribute name, then the
   894     // attribute does not exist and we can't get its namespace ID and
   895     // local name below, so we return early.
   896     return;
   897   }
   899   // Hold a strong reference here so that the atom or nodeinfo doesn't go
   900   // away during UnsetAttr. If it did UnsetAttr would be left with a
   901   // dangling pointer as argument without knowing it.
   902   nsAttrName tmp(*name);
   904   aError = UnsetAttr(name->NamespaceID(), name->LocalName(), true);
   905 }
   907 Attr*
   908 Element::GetAttributeNode(const nsAString& aName)
   909 {
   910   OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNode);
   911   return Attributes()->GetNamedItem(aName);
   912 }
   914 already_AddRefed<Attr>
   915 Element::SetAttributeNode(Attr& aNewAttr, ErrorResult& aError)
   916 {
   917   OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNode);
   919   return Attributes()->SetNamedItem(aNewAttr, aError);
   920 }
   922 already_AddRefed<Attr>
   923 Element::RemoveAttributeNode(Attr& aAttribute,
   924                              ErrorResult& aError)
   925 {
   926   OwnerDoc()->WarnOnceAbout(nsIDocument::eRemoveAttributeNode);
   927   return Attributes()->RemoveNamedItem(aAttribute.NodeName(), aError);
   928 }
   930 void
   931 Element::GetAttributeNS(const nsAString& aNamespaceURI,
   932                         const nsAString& aLocalName,
   933                         nsAString& aReturn)
   934 {
   935   int32_t nsid =
   936     nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
   938   if (nsid == kNameSpaceID_Unknown) {
   939     // Unknown namespace means no attribute.
   940     SetDOMStringToNull(aReturn);
   941     return;
   942   }
   944   nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
   945   bool hasAttr = GetAttr(nsid, name, aReturn);
   946   if (!hasAttr) {
   947     SetDOMStringToNull(aReturn);
   948   }
   949 }
   951 void
   952 Element::SetAttributeNS(const nsAString& aNamespaceURI,
   953                         const nsAString& aQualifiedName,
   954                         const nsAString& aValue,
   955                         ErrorResult& aError)
   956 {
   957   nsCOMPtr<nsINodeInfo> ni;
   958   aError =
   959     nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, aQualifiedName,
   960                                          mNodeInfo->NodeInfoManager(),
   961                                          nsIDOMNode::ATTRIBUTE_NODE,
   962                                          getter_AddRefs(ni));
   963   if (aError.Failed()) {
   964     return;
   965   }
   967   aError = SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(),
   968                    aValue, true);
   969 }
   971 void
   972 Element::RemoveAttributeNS(const nsAString& aNamespaceURI,
   973                            const nsAString& aLocalName,
   974                            ErrorResult& aError)
   975 {
   976   nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
   977   int32_t nsid =
   978     nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
   980   if (nsid == kNameSpaceID_Unknown) {
   981     // If the namespace ID is unknown, it means there can't possibly be an
   982     // existing attribute. We would need a known namespace ID to pass into
   983     // UnsetAttr, so we return early if we don't have one.
   984     return;
   985   }
   987   aError = UnsetAttr(nsid, name, true);
   988 }
   990 Attr*
   991 Element::GetAttributeNodeNS(const nsAString& aNamespaceURI,
   992                             const nsAString& aLocalName)
   993 {
   994   OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNodeNS);
   996   return GetAttributeNodeNSInternal(aNamespaceURI, aLocalName);
   997 }
   999 Attr*
  1000 Element::GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
  1001                                     const nsAString& aLocalName)
  1003   return Attributes()->GetNamedItemNS(aNamespaceURI, aLocalName);
  1006 already_AddRefed<Attr>
  1007 Element::SetAttributeNodeNS(Attr& aNewAttr,
  1008                             ErrorResult& aError)
  1010   OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNodeNS);
  1011   return Attributes()->SetNamedItemNS(aNewAttr, aError);
  1014 already_AddRefed<nsIHTMLCollection>
  1015 Element::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
  1016                                 const nsAString& aLocalName,
  1017                                 ErrorResult& aError)
  1019   int32_t nameSpaceId = kNameSpaceID_Wildcard;
  1021   if (!aNamespaceURI.EqualsLiteral("*")) {
  1022     aError =
  1023       nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
  1024                                                             nameSpaceId);
  1025     if (aError.Failed()) {
  1026       return nullptr;
  1030   NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
  1032   return NS_GetContentList(this, nameSpaceId, aLocalName);
  1035 nsresult
  1036 Element::GetElementsByTagNameNS(const nsAString& namespaceURI,
  1037                                 const nsAString& localName,
  1038                                 nsIDOMHTMLCollection** aResult)
  1040   mozilla::ErrorResult rv;
  1041   nsCOMPtr<nsIHTMLCollection> list =
  1042     GetElementsByTagNameNS(namespaceURI, localName, rv);
  1043   if (rv.Failed()) {
  1044     return rv.ErrorCode();
  1046   list.forget(aResult);
  1047   return NS_OK;
  1050 bool
  1051 Element::HasAttributeNS(const nsAString& aNamespaceURI,
  1052                         const nsAString& aLocalName) const
  1054   int32_t nsid =
  1055     nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
  1057   if (nsid == kNameSpaceID_Unknown) {
  1058     // Unknown namespace means no attr...
  1059     return false;
  1062   nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
  1063   return HasAttr(nsid, name);
  1066 already_AddRefed<nsIHTMLCollection>
  1067 Element::GetElementsByClassName(const nsAString& aClassNames)
  1069   return nsContentUtils::GetElementsByClassName(this, aClassNames);
  1072 nsresult
  1073 Element::GetElementsByClassName(const nsAString& aClassNames,
  1074                                 nsIDOMHTMLCollection** aResult)
  1076   *aResult =
  1077     nsContentUtils::GetElementsByClassName(this, aClassNames).take();
  1078   return NS_OK;
  1081 nsresult
  1082 Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
  1083                     nsIContent* aBindingParent,
  1084                     bool aCompileEventHandlers)
  1086   NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
  1087   NS_PRECONDITION((NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc()),
  1088                   "Must have the same owner document");
  1089   NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
  1090                   "aDocument must be current doc of aParent");
  1091   NS_PRECONDITION(!GetCurrentDoc(), "Already have a document.  Unbind first!");
  1092   // Note that as we recurse into the kids, they'll have a non-null parent.  So
  1093   // only assert if our parent is _changing_ while we have a parent.
  1094   NS_PRECONDITION(!GetParent() || aParent == GetParent(),
  1095                   "Already have a parent.  Unbind first!");
  1096   NS_PRECONDITION(!GetBindingParent() ||
  1097                   aBindingParent == GetBindingParent() ||
  1098                   (!aBindingParent && aParent &&
  1099                    aParent->GetBindingParent() == GetBindingParent()),
  1100                   "Already have a binding parent.  Unbind first!");
  1101   NS_PRECONDITION(!aParent || !aDocument ||
  1102                   !aParent->HasFlag(NODE_FORCE_XBL_BINDINGS),
  1103                   "Parent in document but flagged as forcing XBL");
  1104   NS_PRECONDITION(aBindingParent != this,
  1105                   "Content must not be its own binding parent");
  1106   NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
  1107                   aBindingParent == aParent,
  1108                   "Native anonymous content must have its parent as its "
  1109                   "own binding parent");
  1110   NS_PRECONDITION(aBindingParent || !aParent ||
  1111                   aBindingParent == aParent->GetBindingParent(),
  1112                   "We should be passed the right binding parent");
  1114 #ifdef MOZ_XUL
  1115   // First set the binding parent
  1116   nsXULElement* xulElem = nsXULElement::FromContent(this);
  1117   if (xulElem) {
  1118     xulElem->SetXULBindingParent(aBindingParent);
  1120   else 
  1121 #endif
  1123     if (aBindingParent) {
  1124       nsDOMSlots *slots = DOMSlots();
  1126       slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
  1129   NS_ASSERTION(!aBindingParent || IsRootOfNativeAnonymousSubtree() ||
  1130                !HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) ||
  1131                (aParent && aParent->IsInNativeAnonymousSubtree()),
  1132                "Trying to re-bind content from native anonymous subtree to "
  1133                "non-native anonymous parent!");
  1134   if (aParent) {
  1135     if (aParent->IsInNativeAnonymousSubtree()) {
  1136       SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
  1138     if (aParent->HasFlag(NODE_CHROME_ONLY_ACCESS)) {
  1139       SetFlags(NODE_CHROME_ONLY_ACCESS);
  1141     if (aParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
  1142       SetFlags(NODE_IS_IN_SHADOW_TREE);
  1144     ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
  1145     if (parentContainingShadow) {
  1146       DOMSlots()->mContainingShadow = parentContainingShadow;
  1150   bool hadForceXBL = HasFlag(NODE_FORCE_XBL_BINDINGS);
  1152   // Now set the parent and set the "Force attach xbl" flag if needed.
  1153   if (aParent) {
  1154     if (!GetParent()) {
  1155       NS_ADDREF(aParent);
  1157     mParent = aParent;
  1159     if (aParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
  1160       SetFlags(NODE_FORCE_XBL_BINDINGS);
  1163   else {
  1164     mParent = aDocument;
  1166   SetParentIsContent(aParent);
  1168   // XXXbz sXBL/XBL2 issue!
  1170   // Finally, set the document
  1171   if (aDocument) {
  1172     // Notify XBL- & nsIAnonymousContentCreator-generated
  1173     // anonymous content that the document is changing.
  1174     // XXXbz ordering issues here?  Probably not, since ChangeDocumentFor is
  1175     // just pretty broken anyway....  Need to get it working.
  1176     // XXXbz XBL doesn't handle this (asserts), and we don't really want
  1177     // to be doing this during parsing anyway... sort this out.    
  1178     //    aDocument->BindingManager()->ChangeDocumentFor(this, nullptr,
  1179     //                                                   aDocument);
  1181     // We no longer need to track the subtree pointer (and in fact we'll assert
  1182     // if we do this any later).
  1183     ClearSubtreeRootPointer();
  1185     // Being added to a document.
  1186     SetInDocument();
  1188     if (GetCustomElementData()) {
  1189       // Enqueue an attached callback for the custom element.
  1190       aDocument->EnqueueLifecycleCallback(nsIDocument::eAttached, this);
  1193     // Unset this flag since we now really are in a document.
  1194     UnsetFlags(NODE_FORCE_XBL_BINDINGS |
  1195                // And clear the lazy frame construction bits.
  1196                NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
  1197                // And the restyle bits
  1198                ELEMENT_ALL_RESTYLE_FLAGS);
  1200     // Propagate scoped style sheet tracking bit.
  1201     SetIsElementInStyleScope(mParent->IsElementInStyleScope());
  1202   } else {
  1203     // If we're not in the doc, update our subtree pointer.
  1204     SetSubtreeRootPointer(aParent->SubtreeRoot());
  1207   // This has to be here, rather than in nsGenericHTMLElement::BindToTree,
  1208   //  because it has to happen after updating the parent pointer, but before
  1209   //  recursively binding the kids.
  1210   if (IsHTML()) {
  1211     SetDirOnBind(this, aParent);
  1214   // If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
  1215   // that also need to be told that they are moving.
  1216   nsresult rv;
  1217   if (hadForceXBL) {
  1218     nsBindingManager* bmgr = OwnerDoc()->BindingManager();
  1220     nsXBLBinding* contBinding = bmgr->GetBindingWithContent(this);
  1221     // First check if we have a binding...
  1222     if (contBinding) {
  1223       nsCOMPtr<nsIContent> anonRoot = contBinding->GetAnonymousContent();
  1224       bool allowScripts = contBinding->AllowScripts();
  1225       for (nsCOMPtr<nsIContent> child = anonRoot->GetFirstChild();
  1226            child;
  1227            child = child->GetNextSibling()) {
  1228         rv = child->BindToTree(aDocument, this, this, allowScripts);
  1229         NS_ENSURE_SUCCESS(rv, rv);
  1234   UpdateEditableState(false);
  1236   // Now recurse into our kids
  1237   for (nsIContent* child = GetFirstChild(); child;
  1238        child = child->GetNextSibling()) {
  1239     rv = child->BindToTree(aDocument, this, aBindingParent,
  1240                            aCompileEventHandlers);
  1241     NS_ENSURE_SUCCESS(rv, rv);
  1244   nsNodeUtils::ParentChainChanged(this);
  1246   if (HasID()) {
  1247     AddToIdTable(DoGetID());
  1250   if (MayHaveStyle() && !IsXUL()) {
  1251     // XXXbz if we already have a style attr parsed, this won't do
  1252     // anything... need to fix that.
  1253     // If MayHaveStyle() is true, we must be an nsStyledElement
  1254     static_cast<nsStyledElement*>(this)->ReparseStyleAttribute(false);
  1257   if (aDocument) {
  1258     // If we're in a document now, let our mapped attrs know what their new
  1259     // sheet is.  This is safe to run for non-mapped-attribute elements too;
  1260     // it'll just do a small bit of unnecessary work.  But most elements in
  1261     // practice are mapped-attribute elements.
  1262     nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
  1263     if (sheet) {
  1264       mAttrsAndChildren.SetMappedAttrStyleSheet(sheet);
  1268   // XXXbz script execution during binding can trigger some of these
  1269   // postcondition asserts....  But we do want that, since things will
  1270   // generally be quite broken when that happens.
  1271   NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
  1272   NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
  1273   NS_POSTCONDITION(aBindingParent == GetBindingParent(),
  1274                    "Bound to wrong binding parent");
  1276   return NS_OK;
  1279 class RemoveFromBindingManagerRunnable : public nsRunnable {
  1280 public:
  1281   RemoveFromBindingManagerRunnable(nsBindingManager* aManager,
  1282                                    Element* aElement,
  1283                                    nsIDocument* aDoc):
  1284     mManager(aManager), mElement(aElement), mDoc(aDoc)
  1285   {}
  1287   NS_IMETHOD Run()
  1289     // It may be the case that the element was removed from the
  1290     // DOM, causing this runnable to be created, then inserted back
  1291     // into the document before the this runnable had a chance to
  1292     // tear down the binding. Only tear down the binding if the element
  1293     // is still no longer in the DOM. nsXBLService::LoadBinding tears
  1294     // down the old binding if the element is inserted back into the
  1295     // DOM and loads a different binding.
  1296     if (!mElement->IsInDoc()) {
  1297       mManager->RemovedFromDocumentInternal(mElement, mDoc);
  1300     return NS_OK;
  1303 private:
  1304   nsRefPtr<nsBindingManager> mManager;
  1305   nsRefPtr<Element> mElement;
  1306   nsCOMPtr<nsIDocument> mDoc;
  1307 };
  1309 void
  1310 Element::UnbindFromTree(bool aDeep, bool aNullParent)
  1312   NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
  1313                   "Shallow unbind won't clear document and binding parent on "
  1314                   "kids!");
  1316   RemoveFromIdTable();
  1318   // Make sure to unbind this node before doing the kids
  1319   nsIDocument *document =
  1320     HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetCurrentDoc();
  1322   if (aNullParent) {
  1323     if (IsFullScreenAncestor()) {
  1324       // The element being removed is an ancestor of the full-screen element,
  1325       // exit full-screen state.
  1326       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
  1327                                       NS_LITERAL_CSTRING("DOM"), OwnerDoc(),
  1328                                       nsContentUtils::eDOM_PROPERTIES,
  1329                                       "RemovedFullScreenElement");
  1330       // Fully exit full-screen.
  1331       nsIDocument::ExitFullscreen(OwnerDoc(), /* async */ false);
  1333     if (HasPointerLock()) {
  1334       nsIDocument::UnlockPointer();
  1336     if (GetParent()) {
  1337       nsINode* p = mParent;
  1338       mParent = nullptr;
  1339       NS_RELEASE(p);
  1340     } else {
  1341       mParent = nullptr;
  1343     SetParentIsContent(false);
  1345   ClearInDocument();
  1347   // Begin keeping track of our subtree root.
  1348   SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
  1350   if (document) {
  1351     // Notify XBL- & nsIAnonymousContentCreator-generated
  1352     // anonymous content that the document is changing.
  1353     if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
  1354       nsContentUtils::AddScriptRunner(
  1355         new RemoveFromBindingManagerRunnable(document->BindingManager(), this,
  1356                                              document));
  1359     document->ClearBoxObjectFor(this);
  1361     if (GetCustomElementData()) {
  1362       // Enqueue a detached callback for the custom element.
  1363       document->EnqueueLifecycleCallback(nsIDocument::eDetached, this);
  1367   // Ensure that CSS transitions don't continue on an element at a
  1368   // different place in the tree (even if reinserted before next
  1369   // animation refresh).
  1370   // FIXME (Bug 522599): Need a test for this.
  1371   if (HasFlag(NODE_HAS_PROPERTIES)) {
  1372     DeleteProperty(nsGkAtoms::transitionsOfBeforeProperty);
  1373     DeleteProperty(nsGkAtoms::transitionsOfAfterProperty);
  1374     DeleteProperty(nsGkAtoms::transitionsProperty);
  1375     DeleteProperty(nsGkAtoms::animationsOfBeforeProperty);
  1376     DeleteProperty(nsGkAtoms::animationsOfAfterProperty);
  1377     DeleteProperty(nsGkAtoms::animationsProperty);
  1380   // Unset this since that's what the old code effectively did.
  1381   UnsetFlags(NODE_FORCE_XBL_BINDINGS | NODE_IS_IN_SHADOW_TREE);
  1383 #ifdef MOZ_XUL
  1384   nsXULElement* xulElem = nsXULElement::FromContent(this);
  1385   if (xulElem) {
  1386     xulElem->SetXULBindingParent(nullptr);
  1388   else
  1389 #endif
  1391     nsDOMSlots *slots = GetExistingDOMSlots();
  1392     if (slots) {
  1393       slots->mBindingParent = nullptr;
  1394       slots->mContainingShadow = nullptr;
  1398   // This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree, 
  1399   //  because it has to happen after unsetting the parent pointer, but before
  1400   //  recursively unbinding the kids.
  1401   if (IsHTML()) {
  1402     ResetDir(this);
  1405   if (aDeep) {
  1406     // Do the kids. Don't call GetChildCount() here since that'll force
  1407     // XUL to generate template children, which there is no need for since
  1408     // all we're going to do is unbind them anyway.
  1409     uint32_t i, n = mAttrsAndChildren.ChildCount();
  1411     for (i = 0; i < n; ++i) {
  1412       // Note that we pass false for aNullParent here, since we don't want
  1413       // the kids to forget us.  We _do_ want them to forget their binding
  1414       // parent, though, since this only walks non-anonymous kids.
  1415       mAttrsAndChildren.ChildAt(i)->UnbindFromTree(true, false);
  1419   nsNodeUtils::ParentChainChanged(this);
  1422 nsICSSDeclaration*
  1423 Element::GetSMILOverrideStyle()
  1425   Element::nsDOMSlots *slots = DOMSlots();
  1427   if (!slots->mSMILOverrideStyle) {
  1428     slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true);
  1431   return slots->mSMILOverrideStyle;
  1434 css::StyleRule*
  1435 Element::GetSMILOverrideStyleRule()
  1437   Element::nsDOMSlots *slots = GetExistingDOMSlots();
  1438   return slots ? slots->mSMILOverrideStyleRule.get() : nullptr;
  1441 nsresult
  1442 Element::SetSMILOverrideStyleRule(css::StyleRule* aStyleRule,
  1443                                            bool aNotify)
  1445   Element::nsDOMSlots *slots = DOMSlots();
  1447   slots->mSMILOverrideStyleRule = aStyleRule;
  1449   if (aNotify) {
  1450     nsIDocument* doc = GetCurrentDoc();
  1451     // Only need to request a restyle if we're in a document.  (We might not
  1452     // be in a document, if we're clearing animation effects on a target node
  1453     // that's been detached since the previous animation sample.)
  1454     if (doc) {
  1455       nsCOMPtr<nsIPresShell> shell = doc->GetShell();
  1456       if (shell) {
  1457         shell->RestyleForAnimation(this, eRestyle_Self);
  1462   return NS_OK;
  1465 bool
  1466 Element::IsLabelable() const
  1468   return false;
  1471 css::StyleRule*
  1472 Element::GetInlineStyleRule()
  1474   return nullptr;
  1477 nsresult
  1478 Element::SetInlineStyleRule(css::StyleRule* aStyleRule,
  1479                             const nsAString* aSerialized,
  1480                             bool aNotify)
  1482   NS_NOTYETIMPLEMENTED("Element::SetInlineStyleRule");
  1483   return NS_ERROR_NOT_IMPLEMENTED;
  1486 NS_IMETHODIMP_(bool)
  1487 Element::IsAttributeMapped(const nsIAtom* aAttribute) const
  1489   return false;
  1492 nsChangeHint
  1493 Element::GetAttributeChangeHint(const nsIAtom* aAttribute,
  1494                                 int32_t aModType) const
  1496   return nsChangeHint(0);
  1499 nsIAtom *
  1500 Element::GetClassAttributeName() const
  1502   return nullptr;
  1505 bool
  1506 Element::FindAttributeDependence(const nsIAtom* aAttribute,
  1507                                  const MappedAttributeEntry* const aMaps[],
  1508                                  uint32_t aMapCount)
  1510   for (uint32_t mapindex = 0; mapindex < aMapCount; ++mapindex) {
  1511     for (const MappedAttributeEntry* map = aMaps[mapindex];
  1512          map->attribute; ++map) {
  1513       if (aAttribute == *map->attribute) {
  1514         return true;
  1519   return false;
  1522 already_AddRefed<nsINodeInfo>
  1523 Element::GetExistingAttrNameFromQName(const nsAString& aStr) const
  1525   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aStr);
  1526   if (!name) {
  1527     return nullptr;
  1530   nsCOMPtr<nsINodeInfo> nodeInfo;
  1531   if (name->IsAtom()) {
  1532     nodeInfo = mNodeInfo->NodeInfoManager()->
  1533       GetNodeInfo(name->Atom(), nullptr, kNameSpaceID_None,
  1534                   nsIDOMNode::ATTRIBUTE_NODE);
  1536   else {
  1537     nodeInfo = name->NodeInfo();
  1540   return nodeInfo.forget();
  1543 // static
  1544 bool
  1545 Element::ShouldBlur(nsIContent *aContent)
  1547   // Determine if the current element is focused, if it is not focused
  1548   // then we should not try to blur
  1549   nsIDocument *document = aContent->GetDocument();
  1550   if (!document)
  1551     return false;
  1553   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(document->GetWindow());
  1554   if (!window)
  1555     return false;
  1557   nsCOMPtr<nsPIDOMWindow> focusedFrame;
  1558   nsIContent* contentToBlur =
  1559     nsFocusManager::GetFocusedDescendant(window, false, getter_AddRefs(focusedFrame));
  1560   if (contentToBlur == aContent)
  1561     return true;
  1563   // if focus on this element would get redirected, then check the redirected
  1564   // content as well when blurring.
  1565   return (contentToBlur && nsFocusManager::GetRedirectedFocus(aContent) == contentToBlur);
  1568 bool
  1569 Element::IsNodeOfType(uint32_t aFlags) const
  1571   return !(aFlags & ~eCONTENT);
  1574 /* static */
  1575 nsresult
  1576 Element::DispatchEvent(nsPresContext* aPresContext,
  1577                        WidgetEvent* aEvent,
  1578                        nsIContent* aTarget,
  1579                        bool aFullDispatch,
  1580                        nsEventStatus* aStatus)
  1582   NS_PRECONDITION(aTarget, "Must have target");
  1583   NS_PRECONDITION(aEvent, "Must have source event");
  1584   NS_PRECONDITION(aStatus, "Null out param?");
  1586   if (!aPresContext) {
  1587     return NS_OK;
  1590   nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
  1591   if (!shell) {
  1592     return NS_OK;
  1595   if (aFullDispatch) {
  1596     return shell->HandleEventWithTarget(aEvent, nullptr, aTarget, aStatus);
  1599   return shell->HandleDOMEventWithTarget(aTarget, aEvent, aStatus);
  1602 /* static */
  1603 nsresult
  1604 Element::DispatchClickEvent(nsPresContext* aPresContext,
  1605                             WidgetInputEvent* aSourceEvent,
  1606                             nsIContent* aTarget,
  1607                             bool aFullDispatch,
  1608                             const EventFlags* aExtraEventFlags,
  1609                             nsEventStatus* aStatus)
  1611   NS_PRECONDITION(aTarget, "Must have target");
  1612   NS_PRECONDITION(aSourceEvent, "Must have source event");
  1613   NS_PRECONDITION(aStatus, "Null out param?");
  1615   WidgetMouseEvent event(aSourceEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK,
  1616                          aSourceEvent->widget, WidgetMouseEvent::eReal);
  1617   event.refPoint = aSourceEvent->refPoint;
  1618   uint32_t clickCount = 1;
  1619   float pressure = 0;
  1620   uint16_t inputSource = 0;
  1621   WidgetMouseEvent* sourceMouseEvent = aSourceEvent->AsMouseEvent();
  1622   if (sourceMouseEvent) {
  1623     clickCount = sourceMouseEvent->clickCount;
  1624     pressure = sourceMouseEvent->pressure;
  1625     inputSource = sourceMouseEvent->inputSource;
  1626   } else if (aSourceEvent->eventStructType == NS_KEY_EVENT) {
  1627     inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
  1629   event.pressure = pressure;
  1630   event.clickCount = clickCount;
  1631   event.inputSource = inputSource;
  1632   event.modifiers = aSourceEvent->modifiers;
  1633   if (aExtraEventFlags) {
  1634     // Be careful not to overwrite existing flags!
  1635     event.mFlags.Union(*aExtraEventFlags);
  1638   return DispatchEvent(aPresContext, &event, aTarget, aFullDispatch, aStatus);
  1641 nsIFrame*
  1642 Element::GetPrimaryFrame(mozFlushType aType)
  1644   nsIDocument* doc = GetCurrentDoc();
  1645   if (!doc) {
  1646     return nullptr;
  1649   // Cause a flush, so we get up-to-date frame
  1650   // information
  1651   if (aType != Flush_None) {
  1652     doc->FlushPendingNotifications(aType);
  1655   return GetPrimaryFrame();
  1658 //----------------------------------------------------------------------
  1659 nsresult
  1660 Element::LeaveLink(nsPresContext* aPresContext)
  1662   nsILinkHandler *handler = aPresContext->GetLinkHandler();
  1663   if (!handler) {
  1664     return NS_OK;
  1667   return handler->OnLeaveLink();
  1670 nsresult
  1671 Element::SetEventHandler(nsIAtom* aEventName,
  1672                          const nsAString& aValue,
  1673                          bool aDefer)
  1675   nsIDocument *ownerDoc = OwnerDoc();
  1676   if (ownerDoc->IsLoadedAsData()) {
  1677     // Make this a no-op rather than throwing an error to avoid
  1678     // the error causing problems setting the attribute.
  1679     return NS_OK;
  1682   NS_PRECONDITION(aEventName, "Must have event name!");
  1683   bool defer = true;
  1684   EventListenerManager* manager =
  1685     GetEventListenerManagerForAttr(aEventName, &defer);
  1686   if (!manager) {
  1687     return NS_OK;
  1690   defer = defer && aDefer; // only defer if everyone agrees...
  1691   manager->SetEventHandler(aEventName, aValue,
  1692                            nsIProgrammingLanguage::JAVASCRIPT,
  1693                            defer, !nsContentUtils::IsChromeDoc(ownerDoc),
  1694                            this);
  1695   return NS_OK;
  1699 //----------------------------------------------------------------------
  1701 const nsAttrName*
  1702 Element::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
  1704   return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
  1707 bool
  1708 Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
  1709                                nsIAtom* aName,
  1710                                nsIAtom* aPrefix,
  1711                                const nsAttrValueOrString& aValue,
  1712                                bool aNotify,
  1713                                nsAttrValue& aOldValue,
  1714                                uint8_t* aModType,
  1715                                bool* aHasListeners)
  1717   bool modification = false;
  1718   *aHasListeners = aNotify &&
  1719     nsContentUtils::HasMutationListeners(this,
  1720                                          NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
  1721                                          this);
  1723   // If we have no listeners and aNotify is false, we are almost certainly
  1724   // coming from the content sink and will almost certainly have no previous
  1725   // value.  Even if we do, setting the value is cheap when we have no
  1726   // listeners and don't plan to notify.  The check for aNotify here is an
  1727   // optimization, the check for *aHasListeners is a correctness issue.
  1728   if (*aHasListeners || aNotify) {
  1729     nsAttrInfo info(GetAttrInfo(aNamespaceID, aName));
  1730     if (info.mValue) {
  1731       // Check whether the old value is the same as the new one.  Note that we
  1732       // only need to actually _get_ the old value if we have listeners or
  1733       // if the element is a custom element (because it may have an
  1734       // attribute changed callback).
  1735       if (*aHasListeners || GetCustomElementData()) {
  1736         // Need to store the old value.
  1737         //
  1738         // If the current attribute value contains a pointer to some other data
  1739         // structure that gets updated in the process of setting the attribute
  1740         // we'll no longer have the old value of the attribute. Therefore, we
  1741         // should serialize the attribute value now to keep a snapshot.
  1742         //
  1743         // We have to serialize the value anyway in order to create the
  1744         // mutation event so there's no cost in doing it now.
  1745         aOldValue.SetToSerialized(*info.mValue);
  1747       bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
  1748       if (valueMatches && aPrefix == info.mName->GetPrefix()) {
  1749         return true;
  1751       modification = true;
  1754   *aModType = modification ?
  1755     static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) :
  1756     static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
  1757   return false;
  1760 bool
  1761 Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
  1762                                 nsIAtom* aPrefix,
  1763                                 const nsAttrValueOrString& aValue,
  1764                                 bool aNotify, nsAttrValue& aOldValue,
  1765                                 uint8_t* aModType, bool* aHasListeners)
  1767   if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
  1768                              aOldValue, aModType, aHasListeners)) {
  1769     return false;
  1772   nsAutoScriptBlocker scriptBlocker;
  1773   nsNodeUtils::AttributeSetToCurrentValue(this, aNamespaceID, aName);
  1774   return true;
  1777 nsresult
  1778 Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
  1779                  nsIAtom* aPrefix, const nsAString& aValue,
  1780                  bool aNotify)
  1782   // Keep this in sync with SetParsedAttr below
  1784   NS_ENSURE_ARG_POINTER(aName);
  1785   NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
  1786                "Don't call SetAttr with unknown namespace");
  1788   if (!mAttrsAndChildren.CanFitMoreAttrs()) {
  1789     return NS_ERROR_FAILURE;
  1792   uint8_t modType;
  1793   bool hasListeners;
  1794   nsAttrValueOrString value(aValue);
  1795   nsAttrValue oldValue;
  1797   if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
  1798                              oldValue, &modType, &hasListeners)) {
  1799     return NS_OK;
  1802   nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
  1803   NS_ENSURE_SUCCESS(rv, rv);
  1805   if (aNotify) {
  1806     nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
  1809   // Hold a script blocker while calling ParseAttribute since that can call
  1810   // out to id-observers
  1811   nsAutoScriptBlocker scriptBlocker;
  1813   nsAttrValue attrValue;
  1814   if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
  1815     attrValue.SetTo(aValue);
  1818   return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
  1819                           attrValue, modType, hasListeners, aNotify,
  1820                           kCallAfterSetAttr);
  1823 nsresult
  1824 Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
  1825                        nsIAtom* aPrefix, nsAttrValue& aParsedValue,
  1826                        bool aNotify)
  1828   // Keep this in sync with SetAttr above
  1830   NS_ENSURE_ARG_POINTER(aName);
  1831   NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
  1832                "Don't call SetAttr with unknown namespace");
  1834   if (!mAttrsAndChildren.CanFitMoreAttrs()) {
  1835     return NS_ERROR_FAILURE;
  1839   uint8_t modType;
  1840   bool hasListeners;
  1841   nsAttrValueOrString value(aParsedValue);
  1842   nsAttrValue oldValue;
  1844   if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
  1845                              oldValue, &modType, &hasListeners)) {
  1846     return NS_OK;
  1849   nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
  1850   NS_ENSURE_SUCCESS(rv, rv);
  1852   if (aNotify) {
  1853     nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
  1856   return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
  1857                           aParsedValue, modType, hasListeners, aNotify,
  1858                           kCallAfterSetAttr);
  1861 nsresult
  1862 Element::SetAttrAndNotify(int32_t aNamespaceID,
  1863                           nsIAtom* aName,
  1864                           nsIAtom* aPrefix,
  1865                           const nsAttrValue& aOldValue,
  1866                           nsAttrValue& aParsedValue,
  1867                           uint8_t aModType,
  1868                           bool aFireMutation,
  1869                           bool aNotify,
  1870                           bool aCallAfterSetAttr)
  1872   nsresult rv;
  1874   nsIDocument* document = GetCurrentDoc();
  1875   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
  1877   nsMutationGuard::DidMutate();
  1879   // Copy aParsedValue for later use since it will be lost when we call
  1880   // SetAndTakeMappedAttr below
  1881   nsAttrValue aValueForAfterSetAttr;
  1882   if (aCallAfterSetAttr) {
  1883     aValueForAfterSetAttr.SetTo(aParsedValue);
  1886   bool hadValidDir = false;
  1887   bool hadDirAuto = false;
  1889   if (aNamespaceID == kNameSpaceID_None) {
  1890     if (aName == nsGkAtoms::dir) {
  1891       hadValidDir = HasValidDir() || IsHTML(nsGkAtoms::bdi);
  1892       hadDirAuto = HasDirAuto(); // already takes bdi into account
  1895     // XXXbz Perhaps we should push up the attribute mapping function
  1896     // stuff to Element?
  1897     if (!IsAttributeMapped(aName) ||
  1898         !SetMappedAttribute(document, aName, aParsedValue, &rv)) {
  1899       rv = mAttrsAndChildren.SetAndTakeAttr(aName, aParsedValue);
  1902   else {
  1903     nsCOMPtr<nsINodeInfo> ni;
  1904     ni = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix,
  1905                                                    aNamespaceID,
  1906                                                    nsIDOMNode::ATTRIBUTE_NODE);
  1908     rv = mAttrsAndChildren.SetAndTakeAttr(ni, aParsedValue);
  1910   NS_ENSURE_SUCCESS(rv, rv);
  1912   if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
  1913     nsRefPtr<nsXBLBinding> binding = GetXBLBinding();
  1914     if (binding) {
  1915       binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
  1919   UpdateState(aNotify);
  1921   nsIDocument* ownerDoc = OwnerDoc();
  1922   if (ownerDoc && GetCustomElementData()) {
  1923     nsCOMPtr<nsIAtom> oldValueAtom = aOldValue.GetAsAtom();
  1924     nsCOMPtr<nsIAtom> newValueAtom = aValueForAfterSetAttr.GetAsAtom();
  1925     LifecycleCallbackArgs args = {
  1926       nsDependentAtomString(aName),
  1927       aModType == nsIDOMMutationEvent::ADDITION ?
  1928         NullString() : nsDependentAtomString(oldValueAtom),
  1929       nsDependentAtomString(newValueAtom)
  1930     };
  1932     ownerDoc->EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, this, &args);
  1935   if (aCallAfterSetAttr) {
  1936     rv = AfterSetAttr(aNamespaceID, aName, &aValueForAfterSetAttr, aNotify);
  1937     NS_ENSURE_SUCCESS(rv, rv);
  1939     if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
  1940       OnSetDirAttr(this, &aValueForAfterSetAttr,
  1941                    hadValidDir, hadDirAuto, aNotify);
  1945   if (aNotify) {
  1946     nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
  1949   if (aFireMutation) {
  1950     InternalMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
  1952     nsAutoString ns;
  1953     nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
  1954     Attr* attrNode =
  1955       GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName));
  1956     mutation.mRelatedNode = attrNode;
  1958     mutation.mAttrName = aName;
  1959     nsAutoString newValue;
  1960     GetAttr(aNamespaceID, aName, newValue);
  1961     if (!newValue.IsEmpty()) {
  1962       mutation.mNewAttrValue = do_GetAtom(newValue);
  1964     if (!aOldValue.IsEmptyString()) {
  1965       mutation.mPrevAttrValue = aOldValue.GetAsAtom();
  1967     mutation.mAttrChange = aModType;
  1969     mozAutoSubtreeModified subtree(OwnerDoc(), this);
  1970     (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
  1973   return NS_OK;
  1976 bool
  1977 Element::ParseAttribute(int32_t aNamespaceID,
  1978                         nsIAtom* aAttribute,
  1979                         const nsAString& aValue,
  1980                         nsAttrValue& aResult)
  1982   return false;
  1985 bool
  1986 Element::SetMappedAttribute(nsIDocument* aDocument,
  1987                             nsIAtom* aName,
  1988                             nsAttrValue& aValue,
  1989                             nsresult* aRetval)
  1991   *aRetval = NS_OK;
  1992   return false;
  1995 EventListenerManager*
  1996 Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
  1997                                         bool* aDefer)
  1999   *aDefer = true;
  2000   return GetOrCreateListenerManager();
  2003 Element::nsAttrInfo
  2004 Element::GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const
  2006   NS_ASSERTION(nullptr != aName, "must have attribute name");
  2007   NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
  2008                "must have a real namespace ID!");
  2010   int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNamespaceID);
  2011   if (index >= 0) {
  2012     return nsAttrInfo(mAttrsAndChildren.AttrNameAt(index),
  2013                       mAttrsAndChildren.AttrAt(index));
  2016   return nsAttrInfo(nullptr, nullptr);
  2020 bool
  2021 Element::GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
  2022                  nsAString& aResult) const
  2024   DOMString str;
  2025   bool haveAttr = GetAttr(aNameSpaceID, aName, str);
  2026   str.ToString(aResult);
  2027   return haveAttr;
  2030 int32_t
  2031 Element::FindAttrValueIn(int32_t aNameSpaceID,
  2032                          nsIAtom* aName,
  2033                          AttrValuesArray* aValues,
  2034                          nsCaseTreatment aCaseSensitive) const
  2036   NS_ASSERTION(aName, "Must have attr name");
  2037   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
  2038   NS_ASSERTION(aValues, "Null value array");
  2040   const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
  2041   if (val) {
  2042     for (int32_t i = 0; aValues[i]; ++i) {
  2043       if (val->Equals(*aValues[i], aCaseSensitive)) {
  2044         return i;
  2047     return ATTR_VALUE_NO_MATCH;
  2049   return ATTR_MISSING;
  2052 nsresult
  2053 Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
  2054                    bool aNotify)
  2056   NS_ASSERTION(nullptr != aName, "must have attribute name");
  2058   int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
  2059   if (index < 0) {
  2060     return NS_OK;
  2063   nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
  2064   NS_ENSURE_SUCCESS(rv, rv);
  2066   nsIDocument *document = GetCurrentDoc();
  2067   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
  2069   if (aNotify) {
  2070     nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
  2071                                      nsIDOMMutationEvent::REMOVAL);
  2074   bool hasMutationListeners = aNotify &&
  2075     nsContentUtils::HasMutationListeners(this,
  2076                                          NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
  2077                                          this);
  2079   // Grab the attr node if needed before we remove it from the attr map
  2080   nsRefPtr<Attr> attrNode;
  2081   if (hasMutationListeners) {
  2082     nsAutoString ns;
  2083     nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
  2084     attrNode = GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName));
  2087   // Clear binding to nsIDOMMozNamedAttrMap
  2088   nsDOMSlots *slots = GetExistingDOMSlots();
  2089   if (slots && slots->mAttributeMap) {
  2090     slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
  2093   // The id-handling code, and in the future possibly other code, need to
  2094   // react to unexpected attribute changes.
  2095   nsMutationGuard::DidMutate();
  2097   bool hadValidDir = false;
  2098   bool hadDirAuto = false;
  2100   if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
  2101     hadValidDir = HasValidDir() || IsHTML(nsGkAtoms::bdi);
  2102     hadDirAuto = HasDirAuto(); // already takes bdi into account
  2105   nsAttrValue oldValue;
  2106   rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
  2107   NS_ENSURE_SUCCESS(rv, rv);
  2109   if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
  2110     nsRefPtr<nsXBLBinding> binding = GetXBLBinding();
  2111     if (binding) {
  2112       binding->AttributeChanged(aName, aNameSpaceID, true, aNotify);
  2116   UpdateState(aNotify);
  2118   nsIDocument* ownerDoc = OwnerDoc();
  2119   if (ownerDoc && GetCustomElementData()) {
  2120     nsCOMPtr<nsIAtom> oldValueAtom = oldValue.GetAsAtom();
  2121     LifecycleCallbackArgs args = {
  2122       nsDependentAtomString(aName),
  2123       nsDependentAtomString(oldValueAtom),
  2124       NullString()
  2125     };
  2127     ownerDoc->EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, this, &args);
  2130   if (aNotify) {
  2131     nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
  2132                                   nsIDOMMutationEvent::REMOVAL);
  2135   rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify);
  2136   NS_ENSURE_SUCCESS(rv, rv);
  2138   if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
  2139     OnSetDirAttr(this, nullptr, hadValidDir, hadDirAuto, aNotify);
  2142   if (hasMutationListeners) {
  2143     InternalMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
  2145     mutation.mRelatedNode = attrNode;
  2146     mutation.mAttrName = aName;
  2148     nsAutoString value;
  2149     oldValue.ToString(value);
  2150     if (!value.IsEmpty())
  2151       mutation.mPrevAttrValue = do_GetAtom(value);
  2152     mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
  2154     mozAutoSubtreeModified subtree(OwnerDoc(), this);
  2155     (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
  2158   return NS_OK;
  2161 const nsAttrName*
  2162 Element::GetAttrNameAt(uint32_t aIndex) const
  2164   return mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
  2167 uint32_t
  2168 Element::GetAttrCount() const
  2170   return mAttrsAndChildren.AttrCount();
  2173 void
  2174 Element::DescribeAttribute(uint32_t index, nsAString& aOutDescription) const
  2176   // name
  2177   mAttrsAndChildren.AttrNameAt(index)->GetQualifiedName(aOutDescription);
  2179   // value
  2180   aOutDescription.AppendLiteral("=\"");
  2181   nsAutoString value;
  2182   mAttrsAndChildren.AttrAt(index)->ToString(value);
  2183   for (int i = value.Length(); i >= 0; --i) {
  2184     if (value[i] == char16_t('"'))
  2185       value.Insert(char16_t('\\'), uint32_t(i));
  2187   aOutDescription.Append(value);
  2188   aOutDescription.AppendLiteral("\"");
  2191 #ifdef DEBUG
  2192 void
  2193 Element::ListAttributes(FILE* out) const
  2195   uint32_t index, count = mAttrsAndChildren.AttrCount();
  2196   for (index = 0; index < count; index++) {
  2197     nsAutoString attributeDescription;
  2198     DescribeAttribute(index, attributeDescription);
  2200     fputs(" ", out);
  2201     fputs(NS_LossyConvertUTF16toASCII(attributeDescription).get(), out);
  2205 void
  2206 Element::List(FILE* out, int32_t aIndent,
  2207               const nsCString& aPrefix) const
  2209   int32_t indent;
  2210   for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  2212   fputs(aPrefix.get(), out);
  2214   fputs(NS_LossyConvertUTF16toASCII(mNodeInfo->QualifiedName()).get(), out);
  2216   fprintf(out, "@%p", (void *)this);
  2218   ListAttributes(out);
  2220   fprintf(out, " state=[%llx]",
  2221           static_cast<unsigned long long>(State().GetInternalValue()));
  2222   fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
  2223   if (IsCommonAncestorForRangeInSelection()) {
  2224     nsRange::RangeHashTable* ranges =
  2225       static_cast<nsRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
  2226     fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
  2228   fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
  2229   fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get());
  2231   nsIContent* child = GetFirstChild();
  2232   if (child) {
  2233     fputs("\n", out);
  2235     for (; child; child = child->GetNextSibling()) {
  2236       child->List(out, aIndent + 1);
  2239     for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  2242   fputs(">\n", out);
  2244   Element* nonConstThis = const_cast<Element*>(this);
  2246   // XXX sXBL/XBL2 issue! Owner or current document?
  2247   nsIDocument *document = OwnerDoc();
  2249   // Note: not listing nsIAnonymousContentCreator-created content...
  2251   nsBindingManager* bindingManager = document->BindingManager();
  2252   nsCOMPtr<nsIDOMNodeList> anonymousChildren;
  2253   bindingManager->GetAnonymousNodesFor(nonConstThis,
  2254                                        getter_AddRefs(anonymousChildren));
  2256   if (anonymousChildren) {
  2257     uint32_t length = 0;
  2258     anonymousChildren->GetLength(&length);
  2260     for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  2261     fputs("anonymous-children<\n", out);
  2263     for (uint32_t i = 0; i < length; ++i) {
  2264       nsCOMPtr<nsIDOMNode> node;
  2265       anonymousChildren->Item(i, getter_AddRefs(node));
  2266       nsCOMPtr<nsIContent> child = do_QueryInterface(node);
  2267       child->List(out, aIndent + 1);
  2270     for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  2271     fputs(">\n", out);
  2273     bool outHeader = false;
  2274     ExplicitChildIterator iter(nonConstThis);
  2275     for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
  2276       if (!outHeader) {
  2277         outHeader = true;
  2279         for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  2280         fputs("content-list<\n", out);
  2283       child->List(out, aIndent + 1);
  2286     if (outHeader) {
  2287       for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  2288       fputs(">\n", out);
  2293 void
  2294 Element::DumpContent(FILE* out, int32_t aIndent,
  2295                      bool aDumpAll) const
  2297   int32_t indent;
  2298   for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  2300   const nsString& buf = mNodeInfo->QualifiedName();
  2301   fputs("<", out);
  2302   fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
  2304   if(aDumpAll) ListAttributes(out);
  2306   fputs(">", out);
  2308   if(aIndent) fputs("\n", out);
  2310   for (nsIContent* child = GetFirstChild();
  2311        child;
  2312        child = child->GetNextSibling()) {
  2313     int32_t indent = aIndent ? aIndent + 1 : 0;
  2314     child->DumpContent(out, indent, aDumpAll);
  2316   for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  2317   fputs("</", out);
  2318   fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
  2319   fputs(">", out);
  2321   if(aIndent) fputs("\n", out);
  2323 #endif
  2325 void
  2326 Element::Describe(nsAString& aOutDescription) const
  2328   aOutDescription.Append(mNodeInfo->QualifiedName());
  2329   aOutDescription.AppendPrintf("@%p", (void *)this);
  2331   uint32_t index, count = mAttrsAndChildren.AttrCount();
  2332   for (index = 0; index < count; index++) {
  2333     aOutDescription.Append(' ');
  2334     nsAutoString attributeDescription;
  2335     DescribeAttribute(index, attributeDescription);
  2336     aOutDescription.Append(attributeDescription);
  2340 bool
  2341 Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
  2342                                               nsIURI** aURI) const
  2344   if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
  2345       (!aVisitor.mEvent->mFlags.mIsTrusted &&
  2346        (aVisitor.mEvent->message != NS_MOUSE_CLICK) &&
  2347        (aVisitor.mEvent->message != NS_KEY_PRESS) &&
  2348        (aVisitor.mEvent->message != NS_UI_ACTIVATE)) ||
  2349       !aVisitor.mPresContext ||
  2350       aVisitor.mEvent->mFlags.mMultipleActionsPrevented) {
  2351     return false;
  2354   // Make sure we actually are a link
  2355   return IsLink(aURI);
  2358 nsresult
  2359 Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
  2361   // Optimisation: return early if this event doesn't interest us.
  2362   // IMPORTANT: this switch and the switch below it must be kept in sync!
  2363   switch (aVisitor.mEvent->message) {
  2364   case NS_MOUSE_ENTER_SYNTH:
  2365   case NS_FOCUS_CONTENT:
  2366   case NS_MOUSE_EXIT_SYNTH:
  2367   case NS_BLUR_CONTENT:
  2368     break;
  2369   default:
  2370     return NS_OK;
  2373   // Make sure we meet the preconditions before continuing
  2374   nsCOMPtr<nsIURI> absURI;
  2375   if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
  2376     return NS_OK;
  2379   nsresult rv = NS_OK;
  2381   // We do the status bar updates in PreHandleEvent so that the status bar gets
  2382   // updated even if the event is consumed before we have a chance to set it.
  2383   switch (aVisitor.mEvent->message) {
  2384   // Set the status bar similarly for mouseover and focus
  2385   case NS_MOUSE_ENTER_SYNTH:
  2386     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  2387     // FALL THROUGH
  2388   case NS_FOCUS_CONTENT: {
  2389     InternalFocusEvent* focusEvent = aVisitor.mEvent->AsFocusEvent();
  2390     if (!focusEvent || !focusEvent->isRefocus) {
  2391       nsAutoString target;
  2392       GetLinkTarget(target);
  2393       nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
  2394                                   false, true, true);
  2395       // Make sure any ancestor links don't also TriggerLink
  2396       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
  2398     break;
  2400   case NS_MOUSE_EXIT_SYNTH:
  2401     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  2402     // FALL THROUGH
  2403   case NS_BLUR_CONTENT:
  2404     rv = LeaveLink(aVisitor.mPresContext);
  2405     if (NS_SUCCEEDED(rv)) {
  2406       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
  2408     break;
  2410   default:
  2411     // switch not in sync with the optimization switch earlier in this function
  2412     NS_NOTREACHED("switch statements not in sync");
  2413     return NS_ERROR_UNEXPECTED;
  2416   return rv;
  2419 nsresult
  2420 Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor)
  2422   // Optimisation: return early if this event doesn't interest us.
  2423   // IMPORTANT: this switch and the switch below it must be kept in sync!
  2424   switch (aVisitor.mEvent->message) {
  2425   case NS_MOUSE_BUTTON_DOWN:
  2426   case NS_MOUSE_CLICK:
  2427   case NS_UI_ACTIVATE:
  2428   case NS_KEY_PRESS:
  2429     break;
  2430   default:
  2431     return NS_OK;
  2434   // Make sure we meet the preconditions before continuing
  2435   nsCOMPtr<nsIURI> absURI;
  2436   if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
  2437     return NS_OK;
  2440   nsresult rv = NS_OK;
  2442   switch (aVisitor.mEvent->message) {
  2443   case NS_MOUSE_BUTTON_DOWN:
  2445       if (aVisitor.mEvent->AsMouseEvent()->button ==
  2446             WidgetMouseEvent::eLeftButton) {
  2447         // don't make the link grab the focus if there is no link handler
  2448         nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler();
  2449         nsIDocument *document = GetCurrentDoc();
  2450         if (handler && document) {
  2451           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  2452           if (fm) {
  2453             aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
  2454             nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
  2455             fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE |
  2456                                nsIFocusManager::FLAG_NOSCROLL);
  2459           EventStateManager::SetActiveManager(
  2460             aVisitor.mPresContext->EventStateManager(), this);
  2464     break;
  2466   case NS_MOUSE_CLICK: {
  2467     WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
  2468     if (mouseEvent->IsLeftClickEvent()) {
  2469       if (mouseEvent->IsControl() || mouseEvent->IsMeta() ||
  2470           mouseEvent->IsAlt() ||mouseEvent->IsShift()) {
  2471         break;
  2474       // The default action is simply to dispatch DOMActivate
  2475       nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
  2476       if (shell) {
  2477         // single-click
  2478         nsEventStatus status = nsEventStatus_eIgnore;
  2479         InternalUIEvent actEvent(mouseEvent->mFlags.mIsTrusted, NS_UI_ACTIVATE);
  2480         actEvent.detail = 1;
  2482         rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
  2483         if (NS_SUCCEEDED(rv)) {
  2484           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  2488     break;
  2490   case NS_UI_ACTIVATE:
  2492       if (aVisitor.mEvent->originalTarget == this) {
  2493         nsAutoString target;
  2494         GetLinkTarget(target);
  2495         nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
  2496                                     true, true,
  2497                                     aVisitor.mEvent->mFlags.mIsTrusted);
  2498         aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  2501     break;
  2503   case NS_KEY_PRESS:
  2505       WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
  2506       if (keyEvent && keyEvent->keyCode == NS_VK_RETURN) {
  2507         nsEventStatus status = nsEventStatus_eIgnore;
  2508         rv = DispatchClickEvent(aVisitor.mPresContext, keyEvent, this,
  2509                                 false, nullptr, &status);
  2510         if (NS_SUCCEEDED(rv)) {
  2511           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  2515     break;
  2517   default:
  2518     // switch not in sync with the optimization switch earlier in this function
  2519     NS_NOTREACHED("switch statements not in sync");
  2520     return NS_ERROR_UNEXPECTED;
  2523   return rv;
  2526 void
  2527 Element::GetLinkTarget(nsAString& aTarget)
  2529   aTarget.Truncate();
  2532 bool
  2533 Element::MozMatchesSelector(const nsAString& aSelector,
  2534                             ErrorResult& aError)
  2536   nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aError);
  2537   if (!selectorList) {
  2538     // Either we failed (and aError already has the exception), or this
  2539     // is a pseudo-element-only selector that matches nothing.
  2540     return false;
  2543   OwnerDoc()->FlushPendingLinkUpdates();
  2544   TreeMatchContext matchingContext(false,
  2545                                    nsRuleWalker::eRelevantLinkUnvisited,
  2546                                    OwnerDoc(),
  2547                                    TreeMatchContext::eNeverMatchVisited);
  2548   matchingContext.SetHasSpecifiedScope();
  2549   matchingContext.AddScopeElement(this);
  2550   return nsCSSRuleProcessor::SelectorListMatches(this, matchingContext,
  2551                                                  selectorList);
  2554 static const nsAttrValue::EnumTable kCORSAttributeTable[] = {
  2555   // Order matters here
  2556   // See ParseCORSValue
  2557   { "anonymous",       CORS_ANONYMOUS       },
  2558   { "use-credentials", CORS_USE_CREDENTIALS },
  2559   { 0 }
  2560 };
  2562 /* static */ void
  2563 Element::ParseCORSValue(const nsAString& aValue,
  2564                         nsAttrValue& aResult)
  2566   DebugOnly<bool> success =
  2567     aResult.ParseEnumValue(aValue, kCORSAttributeTable, false,
  2568                            // default value is anonymous if aValue is
  2569                            // not a value we understand
  2570                            &kCORSAttributeTable[0]);
  2571   MOZ_ASSERT(success);
  2574 /* static */ CORSMode
  2575 Element::StringToCORSMode(const nsAString& aValue)
  2577   if (aValue.IsVoid()) {
  2578     return CORS_NONE;
  2581   nsAttrValue val;
  2582   Element::ParseCORSValue(aValue, val);
  2583   return CORSMode(val.GetEnumValue());
  2586 /* static */ CORSMode
  2587 Element::AttrValueToCORSMode(const nsAttrValue* aValue)
  2589   if (!aValue) {
  2590     return CORS_NONE;
  2593   return CORSMode(aValue->GetEnumValue());
  2596 static const char*
  2597 GetFullScreenError(nsIDocument* aDoc)
  2599   // Block fullscreen requests in the chrome document when the fullscreen API
  2600   // is configured for content only.
  2601   if (nsContentUtils::IsFullscreenApiContentOnly() &&
  2602       nsContentUtils::IsChromeDoc(aDoc)) {
  2603     return "FullScreenDeniedContentOnly";
  2606   nsCOMPtr<nsPIDOMWindow> win = aDoc->GetWindow();
  2607   if (aDoc->NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED) {
  2608     // Request is in a web app and in the same origin as the web app.
  2609     // Don't enforce as strict security checks for web apps, the user
  2610     // is supposed to have trust in them. However documents cross-origin
  2611     // to the web app must still confirm to the normal security checks.
  2612     return nullptr;
  2615   if (!nsContentUtils::IsRequestFullScreenAllowed()) {
  2616     return "FullScreenDeniedNotInputDriven";
  2619   if (nsContentUtils::IsSitePermDeny(aDoc->NodePrincipal(), "fullscreen")) {
  2620     return "FullScreenDeniedBlocked";
  2623   return nullptr;
  2626 void
  2627 Element::MozRequestFullScreen()
  2629   // Only grant full-screen requests if this is called from inside a trusted
  2630   // event handler (i.e. inside an event handler for a user initiated event).
  2631   // This stops the full-screen from being abused similar to the popups of old,
  2632   // and it also makes it harder for bad guys' script to go full-screen and
  2633   // spoof the browser chrome/window and phish logins etc.
  2634   // Note that requests for fullscreen inside a web app's origin are exempt
  2635   // from this restriction.
  2636   const char* error = GetFullScreenError(OwnerDoc());
  2637   if (error) {
  2638     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
  2639                                     NS_LITERAL_CSTRING("DOM"), OwnerDoc(),
  2640                                     nsContentUtils::eDOM_PROPERTIES,
  2641                                     error);
  2642     nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
  2643       new AsyncEventDispatcher(OwnerDoc(),
  2644                                NS_LITERAL_STRING("mozfullscreenerror"),
  2645                                true,
  2646                                false);
  2647     asyncDispatcher->PostDOMEvent();
  2648     return;
  2651   OwnerDoc()->AsyncRequestFullScreen(this);
  2653   return;
  2656 void
  2657 Element::MozRequestPointerLock()
  2659   OwnerDoc()->RequestPointerLock(this);
  2662 NS_IMETHODIMP
  2663 Element::GetInnerHTML(nsAString& aInnerHTML)
  2665   GetMarkup(false, aInnerHTML);
  2666   return NS_OK;
  2669 void
  2670 Element::SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
  2672   SetInnerHTMLInternal(aInnerHTML, aError);
  2675 void
  2676 Element::GetOuterHTML(nsAString& aOuterHTML)
  2678   GetMarkup(true, aOuterHTML);
  2681 void
  2682 Element::SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError)
  2684   nsCOMPtr<nsINode> parent = GetParentNode();
  2685   if (!parent) {
  2686     return;
  2689   if (parent->NodeType() == nsIDOMNode::DOCUMENT_NODE) {
  2690     aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
  2691     return;
  2694   if (OwnerDoc()->IsHTML()) {
  2695     nsIAtom* localName;
  2696     int32_t namespaceID;
  2697     if (parent->IsElement()) {
  2698       localName = static_cast<nsIContent*>(parent.get())->Tag();
  2699       namespaceID = static_cast<nsIContent*>(parent.get())->GetNameSpaceID();
  2700     } else {
  2701       NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
  2702         "How come the parent isn't a document, a fragment or an element?");
  2703       localName = nsGkAtoms::body;
  2704       namespaceID = kNameSpaceID_XHTML;
  2706     nsRefPtr<DocumentFragment> fragment =
  2707       new DocumentFragment(OwnerDoc()->NodeInfoManager());
  2708     nsContentUtils::ParseFragmentHTML(aOuterHTML,
  2709                                       fragment,
  2710                                       localName,
  2711                                       namespaceID,
  2712                                       OwnerDoc()->GetCompatibilityMode() ==
  2713                                         eCompatibility_NavQuirks,
  2714                                       true);
  2715     parent->ReplaceChild(*fragment, *this, aError);
  2716     return;
  2719   nsCOMPtr<nsINode> context;
  2720   if (parent->IsElement()) {
  2721     context = parent;
  2722   } else {
  2723     NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
  2724       "How come the parent isn't a document, a fragment or an element?");
  2725     nsCOMPtr<nsINodeInfo> info =
  2726       OwnerDoc()->NodeInfoManager()->GetNodeInfo(nsGkAtoms::body,
  2727                                                  nullptr,
  2728                                                  kNameSpaceID_XHTML,
  2729                                                  nsIDOMNode::ELEMENT_NODE);
  2730     context = NS_NewHTMLBodyElement(info.forget(), FROM_PARSER_FRAGMENT);
  2733   nsCOMPtr<nsIDOMDocumentFragment> df;
  2734   aError = nsContentUtils::CreateContextualFragment(context,
  2735                                                     aOuterHTML,
  2736                                                     true,
  2737                                                     getter_AddRefs(df));
  2738   if (aError.Failed()) {
  2739     return;
  2741   nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
  2742   parent->ReplaceChild(*fragment, *this, aError);
  2745 enum nsAdjacentPosition {
  2746   eBeforeBegin,
  2747   eAfterBegin,
  2748   eBeforeEnd,
  2749   eAfterEnd
  2750 };
  2752 void
  2753 Element::InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
  2754                             ErrorResult& aError)
  2756   nsAdjacentPosition position;
  2757   if (aPosition.LowerCaseEqualsLiteral("beforebegin")) {
  2758     position = eBeforeBegin;
  2759   } else if (aPosition.LowerCaseEqualsLiteral("afterbegin")) {
  2760     position = eAfterBegin;
  2761   } else if (aPosition.LowerCaseEqualsLiteral("beforeend")) {
  2762     position = eBeforeEnd;
  2763   } else if (aPosition.LowerCaseEqualsLiteral("afterend")) {
  2764     position = eAfterEnd;
  2765   } else {
  2766     aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  2767     return;
  2770   nsCOMPtr<nsIContent> destination;
  2771   if (position == eBeforeBegin || position == eAfterEnd) {
  2772     destination = GetParent();
  2773     if (!destination) {
  2774       aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
  2775       return;
  2777   } else {
  2778     destination = this;
  2781   nsIDocument* doc = OwnerDoc();
  2783   // Needed when insertAdjacentHTML is used in combination with contenteditable
  2784   mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
  2785   nsAutoScriptLoaderDisabler sld(doc);
  2787   // Batch possible DOMSubtreeModified events.
  2788   mozAutoSubtreeModified subtree(doc, nullptr);
  2790   // Parse directly into destination if possible
  2791   if (doc->IsHTML() && !OwnerDoc()->MayHaveDOMMutationObservers() &&
  2792       (position == eBeforeEnd ||
  2793        (position == eAfterEnd && !GetNextSibling()) ||
  2794        (position == eAfterBegin && !GetFirstChild()))) {
  2795     int32_t oldChildCount = destination->GetChildCount();
  2796     int32_t contextNs = destination->GetNameSpaceID();
  2797     nsIAtom* contextLocal = destination->Tag();
  2798     if (contextLocal == nsGkAtoms::html && contextNs == kNameSpaceID_XHTML) {
  2799       // For compat with IE6 through IE9. Willful violation of HTML5 as of
  2800       // 2011-04-06. CreateContextualFragment does the same already.
  2801       // Spec bug: http://www.w3.org/Bugs/Public/show_bug.cgi?id=12434
  2802       contextLocal = nsGkAtoms::body;
  2804     aError = nsContentUtils::ParseFragmentHTML(aText,
  2805                                                destination,
  2806                                                contextLocal,
  2807                                                contextNs,
  2808                                                doc->GetCompatibilityMode() ==
  2809                                                  eCompatibility_NavQuirks,
  2810                                                true);
  2811     // HTML5 parser has notified, but not fired mutation events.
  2812     nsContentUtils::FireMutationEventsForDirectParsing(doc, destination,
  2813                                                        oldChildCount);
  2814     return;
  2817   // couldn't parse directly
  2818   nsCOMPtr<nsIDOMDocumentFragment> df;
  2819   aError = nsContentUtils::CreateContextualFragment(destination,
  2820                                                     aText,
  2821                                                     true,
  2822                                                     getter_AddRefs(df));
  2823   if (aError.Failed()) {
  2824     return;
  2827   nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
  2829   // Suppress assertion about node removal mutation events that can't have
  2830   // listeners anyway, because no one has had the chance to register mutation
  2831   // listeners on the fragment that comes from the parser.
  2832   nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
  2834   nsAutoMutationBatch mb(destination, true, false);
  2835   switch (position) {
  2836     case eBeforeBegin:
  2837       destination->InsertBefore(*fragment, this, aError);
  2838       break;
  2839     case eAfterBegin:
  2840       static_cast<nsINode*>(this)->InsertBefore(*fragment, GetFirstChild(),
  2841                                                 aError);
  2842       break;
  2843     case eBeforeEnd:
  2844       static_cast<nsINode*>(this)->AppendChild(*fragment, aError);
  2845       break;
  2846     case eAfterEnd:
  2847       destination->InsertBefore(*fragment, GetNextSibling(), aError);
  2848       break;
  2852 nsIEditor*
  2853 Element::GetEditorInternal()
  2855   nsCOMPtr<nsITextControlElement> textCtrl = do_QueryInterface(this);
  2856   return textCtrl ? textCtrl->GetTextEditor() : nullptr;
  2859 nsresult
  2860 Element::SetBoolAttr(nsIAtom* aAttr, bool aValue)
  2862   if (aValue) {
  2863     return SetAttr(kNameSpaceID_None, aAttr, EmptyString(), true);
  2866   return UnsetAttr(kNameSpaceID_None, aAttr, true);
  2869 Directionality
  2870 Element::GetComputedDirectionality() const
  2872   nsIFrame* frame = GetPrimaryFrame();
  2873   if (frame) {
  2874     return frame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR
  2875              ? eDir_LTR : eDir_RTL;
  2878   return GetDirectionality();
  2881 float
  2882 Element::FontSizeInflation()
  2884   nsIFrame* frame = GetPrimaryFrame();
  2885   if (!frame) {
  2886     return -1.0;
  2889   if (nsLayoutUtils::FontSizeInflationEnabled(frame->PresContext())) {
  2890     return nsLayoutUtils::FontSizeInflationFor(frame);
  2893   return 1.0;

mercurial