content/base/src/Element.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/Element.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2894 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=79: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * Base class for all element classes; this provides an implementation
    1.12 + * of DOM Core's nsIDOMElement, implements nsIContent, provides
    1.13 + * utility methods for subclasses, and so forth.
    1.14 + */
    1.15 +
    1.16 +#include "mozilla/dom/ElementInlines.h"
    1.17 +
    1.18 +#include "mozilla/DebugOnly.h"
    1.19 +#include "mozilla/dom/Attr.h"
    1.20 +#include "nsDOMAttributeMap.h"
    1.21 +#include "nsIAtom.h"
    1.22 +#include "nsIContentInlines.h"
    1.23 +#include "nsINodeInfo.h"
    1.24 +#include "nsIDocumentInlines.h"
    1.25 +#include "nsIDOMNodeList.h"
    1.26 +#include "nsIDOMDocument.h"
    1.27 +#include "nsIContentIterator.h"
    1.28 +#include "nsFocusManager.h"
    1.29 +#include "nsILinkHandler.h"
    1.30 +#include "nsIScriptGlobalObject.h"
    1.31 +#include "nsIURL.h"
    1.32 +#include "nsNetUtil.h"
    1.33 +#include "nsIFrame.h"
    1.34 +#include "nsIAnonymousContentCreator.h"
    1.35 +#include "nsIPresShell.h"
    1.36 +#include "nsPresContext.h"
    1.37 +#include "nsStyleConsts.h"
    1.38 +#include "nsString.h"
    1.39 +#include "nsUnicharUtils.h"
    1.40 +#include "nsIDOMEvent.h"
    1.41 +#include "nsDOMCID.h"
    1.42 +#include "nsIServiceManager.h"
    1.43 +#include "nsIDOMCSSStyleDeclaration.h"
    1.44 +#include "nsDOMCSSAttrDeclaration.h"
    1.45 +#include "nsNameSpaceManager.h"
    1.46 +#include "nsContentList.h"
    1.47 +#include "nsDOMTokenList.h"
    1.48 +#include "nsXBLPrototypeBinding.h"
    1.49 +#include "nsError.h"
    1.50 +#include "nsDOMString.h"
    1.51 +#include "nsIScriptSecurityManager.h"
    1.52 +#include "nsIDOMMutationEvent.h"
    1.53 +#include "mozilla/AsyncEventDispatcher.h"
    1.54 +#include "mozilla/ContentEvents.h"
    1.55 +#include "mozilla/EventDispatcher.h"
    1.56 +#include "mozilla/EventListenerManager.h"
    1.57 +#include "mozilla/EventStateManager.h"
    1.58 +#include "mozilla/EventStates.h"
    1.59 +#include "mozilla/InternalMutationEvent.h"
    1.60 +#include "mozilla/MouseEvents.h"
    1.61 +#include "mozilla/TextEvents.h"
    1.62 +#include "nsNodeUtils.h"
    1.63 +#include "mozilla/dom/DirectionalityUtils.h"
    1.64 +#include "nsDocument.h"
    1.65 +#include "nsAttrValueOrString.h"
    1.66 +#include "nsAttrValueInlines.h"
    1.67 +#ifdef MOZ_XUL
    1.68 +#include "nsXULElement.h"
    1.69 +#endif /* MOZ_XUL */
    1.70 +#include "nsFrameManager.h"
    1.71 +#include "nsFrameSelection.h"
    1.72 +#ifdef DEBUG
    1.73 +#include "nsRange.h"
    1.74 +#endif
    1.75 +
    1.76 +#include "nsBindingManager.h"
    1.77 +#include "nsXBLBinding.h"
    1.78 +#include "nsPIDOMWindow.h"
    1.79 +#include "nsPIBoxObject.h"
    1.80 +#include "mozilla/dom/DOMRect.h"
    1.81 +#include "nsSVGUtils.h"
    1.82 +#include "nsLayoutUtils.h"
    1.83 +#include "nsGkAtoms.h"
    1.84 +#include "nsContentUtils.h"
    1.85 +#include "ChildIterator.h"
    1.86 +
    1.87 +#include "nsIDOMEventListener.h"
    1.88 +#include "nsIWebNavigation.h"
    1.89 +#include "nsIBaseWindow.h"
    1.90 +#include "nsIWidget.h"
    1.91 +
    1.92 +#include "nsNodeInfoManager.h"
    1.93 +#include "nsICategoryManager.h"
    1.94 +#include "nsIDOMDocumentType.h"
    1.95 +#include "nsIDOMUserDataHandler.h"
    1.96 +#include "nsGenericHTMLElement.h"
    1.97 +#include "nsIEditor.h"
    1.98 +#include "nsIEditorIMESupport.h"
    1.99 +#include "nsContentCreatorFunctions.h"
   1.100 +#include "nsIControllers.h"
   1.101 +#include "nsView.h"
   1.102 +#include "nsViewManager.h"
   1.103 +#include "nsIScrollableFrame.h"
   1.104 +#include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */
   1.105 +#include "nsCSSRuleProcessor.h"
   1.106 +#include "nsRuleProcessorData.h"
   1.107 +#include "nsTextNode.h"
   1.108 +
   1.109 +#ifdef MOZ_XUL
   1.110 +#include "nsIXULDocument.h"
   1.111 +#endif /* MOZ_XUL */
   1.112 +
   1.113 +#include "nsCycleCollectionParticipant.h"
   1.114 +#include "nsCCUncollectableMarker.h"
   1.115 +
   1.116 +#include "mozAutoDocUpdate.h"
   1.117 +
   1.118 +#include "nsCSSParser.h"
   1.119 +#include "prprf.h"
   1.120 +#include "nsDOMMutationObserver.h"
   1.121 +#include "nsSVGFeatures.h"
   1.122 +#include "nsWrapperCacheInlines.h"
   1.123 +#include "xpcpublic.h"
   1.124 +#include "nsIScriptError.h"
   1.125 +#include "mozilla/Telemetry.h"
   1.126 +
   1.127 +#include "mozilla/CORSMode.h"
   1.128 +#include "mozilla/dom/ShadowRoot.h"
   1.129 +
   1.130 +#include "nsStyledElement.h"
   1.131 +#include "nsXBLService.h"
   1.132 +#include "nsITextControlElement.h"
   1.133 +#include "nsITextControlFrame.h"
   1.134 +#include "nsISupportsImpl.h"
   1.135 +#include "mozilla/dom/DocumentFragment.h"
   1.136 +#include "mozilla/IntegerPrintfMacros.h"
   1.137 +
   1.138 +using namespace mozilla;
   1.139 +using namespace mozilla::dom;
   1.140 +
   1.141 +NS_IMETHODIMP
   1.142 +Element::QueryInterface(REFNSIID aIID, void** aInstancePtr)
   1.143 +{
   1.144 +  NS_ASSERTION(aInstancePtr,
   1.145 +               "QueryInterface requires a non-NULL destination!");
   1.146 +  nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr);
   1.147 +  if (NS_SUCCEEDED(rv)) {
   1.148 +    return NS_OK;
   1.149 +  }
   1.150 +
   1.151 +  // Give the binding manager a chance to get an interface for this element.
   1.152 +  return OwnerDoc()->BindingManager()->GetBindingImplementation(this, aIID,
   1.153 +                                                                aInstancePtr);
   1.154 +}
   1.155 +
   1.156 +EventStates
   1.157 +Element::IntrinsicState() const
   1.158 +{
   1.159 +  return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE :
   1.160 +                        NS_EVENT_STATE_MOZ_READONLY;
   1.161 +}
   1.162 +
   1.163 +void
   1.164 +Element::NotifyStateChange(EventStates aStates)
   1.165 +{
   1.166 +  nsIDocument* doc = GetCurrentDoc();
   1.167 +  if (doc) {
   1.168 +    nsAutoScriptBlocker scriptBlocker;
   1.169 +    doc->ContentStateChanged(this, aStates);
   1.170 +  }
   1.171 +}
   1.172 +
   1.173 +void
   1.174 +Element::UpdateLinkState(EventStates aState)
   1.175 +{
   1.176 +  NS_ABORT_IF_FALSE(!aState.HasAtLeastOneOfStates(~(NS_EVENT_STATE_VISITED |
   1.177 +                                                    NS_EVENT_STATE_UNVISITED)),
   1.178 +                    "Unexpected link state bits");
   1.179 +  mState =
   1.180 +    (mState & ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) |
   1.181 +    aState;
   1.182 +}
   1.183 +
   1.184 +void
   1.185 +Element::UpdateState(bool aNotify)
   1.186 +{
   1.187 +  EventStates oldState = mState;
   1.188 +  mState = IntrinsicState() | (oldState & ESM_MANAGED_STATES);
   1.189 +  if (aNotify) {
   1.190 +    EventStates changedStates = oldState ^ mState;
   1.191 +    if (!changedStates.IsEmpty()) {
   1.192 +      nsIDocument* doc = GetCurrentDoc();
   1.193 +      if (doc) {
   1.194 +        nsAutoScriptBlocker scriptBlocker;
   1.195 +        doc->ContentStateChanged(this, changedStates);
   1.196 +      }
   1.197 +    }
   1.198 +  }
   1.199 +}
   1.200 +
   1.201 +void
   1.202 +nsIContent::UpdateEditableState(bool aNotify)
   1.203 +{
   1.204 +  // Guaranteed to be non-element content
   1.205 +  NS_ASSERTION(!IsElement(), "What happened here?");
   1.206 +  nsIContent *parent = GetParent();
   1.207 +
   1.208 +  // Skip over unknown native anonymous content to avoid setting a flag we
   1.209 +  // can't clear later
   1.210 +  bool isUnknownNativeAnon = false;
   1.211 +  if (IsInNativeAnonymousSubtree()) {
   1.212 +    isUnknownNativeAnon = true;
   1.213 +    nsCOMPtr<nsIContent> root = this;
   1.214 +    while (root && !root->IsRootOfNativeAnonymousSubtree()) {
   1.215 +      root = root->GetParent();
   1.216 +    }
   1.217 +    // root should always be true here, but isn't -- bug 999416
   1.218 +    if (root) {
   1.219 +      nsIFrame* rootFrame = root->GetPrimaryFrame();
   1.220 +      if (rootFrame) {
   1.221 +        nsIFrame* parentFrame = rootFrame->GetParent();
   1.222 +        nsITextControlFrame* textCtrl = do_QueryFrame(parentFrame);
   1.223 +        isUnknownNativeAnon = !textCtrl;
   1.224 +      }
   1.225 +    }
   1.226 +  }
   1.227 +
   1.228 +  SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE) &&
   1.229 +                  !isUnknownNativeAnon);
   1.230 +}
   1.231 +
   1.232 +void
   1.233 +Element::UpdateEditableState(bool aNotify)
   1.234 +{
   1.235 +  nsIContent *parent = GetParent();
   1.236 +
   1.237 +  SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
   1.238 +  if (aNotify) {
   1.239 +    UpdateState(aNotify);
   1.240 +  } else {
   1.241 +    // Avoid calling UpdateState in this very common case, because
   1.242 +    // this gets called for pretty much every single element on
   1.243 +    // insertion into the document and UpdateState can be slow for
   1.244 +    // some kinds of elements even when not notifying.
   1.245 +    if (IsEditable()) {
   1.246 +      RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
   1.247 +      AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
   1.248 +    } else {
   1.249 +      RemoveStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
   1.250 +      AddStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
   1.251 +    }
   1.252 +  }
   1.253 +}
   1.254 +
   1.255 +EventStates
   1.256 +Element::StyleStateFromLocks() const
   1.257 +{
   1.258 +  EventStates locks = LockedStyleStates();
   1.259 +  EventStates state = mState | locks;
   1.260 +
   1.261 +  if (locks.HasState(NS_EVENT_STATE_VISITED)) {
   1.262 +    return state & ~NS_EVENT_STATE_UNVISITED;
   1.263 +  }
   1.264 +  if (locks.HasState(NS_EVENT_STATE_UNVISITED)) {
   1.265 +    return state & ~NS_EVENT_STATE_VISITED;
   1.266 +  }
   1.267 +  return state;
   1.268 +}
   1.269 +
   1.270 +EventStates
   1.271 +Element::LockedStyleStates() const
   1.272 +{
   1.273 +  EventStates* locks =
   1.274 +    static_cast<EventStates*>(GetProperty(nsGkAtoms::lockedStyleStates));
   1.275 +  if (locks) {
   1.276 +    return *locks;
   1.277 +  }
   1.278 +  return EventStates();
   1.279 +}
   1.280 +
   1.281 +void
   1.282 +Element::NotifyStyleStateChange(EventStates aStates)
   1.283 +{
   1.284 +  nsIDocument* doc = GetCurrentDoc();
   1.285 +  if (doc) {
   1.286 +    nsIPresShell *presShell = doc->GetShell();
   1.287 +    if (presShell) {
   1.288 +      nsAutoScriptBlocker scriptBlocker;
   1.289 +      presShell->ContentStateChanged(doc, this, aStates);
   1.290 +    }
   1.291 +  }
   1.292 +}
   1.293 +
   1.294 +void
   1.295 +Element::LockStyleStates(EventStates aStates)
   1.296 +{
   1.297 +  EventStates* locks = new EventStates(LockedStyleStates());
   1.298 +
   1.299 +  *locks |= aStates;
   1.300 +
   1.301 +  if (aStates.HasState(NS_EVENT_STATE_VISITED)) {
   1.302 +    *locks &= ~NS_EVENT_STATE_UNVISITED;
   1.303 +  }
   1.304 +  if (aStates.HasState(NS_EVENT_STATE_UNVISITED)) {
   1.305 +    *locks &= ~NS_EVENT_STATE_VISITED;
   1.306 +  }
   1.307 +
   1.308 +  SetProperty(nsGkAtoms::lockedStyleStates, locks,
   1.309 +              nsINode::DeleteProperty<EventStates>);
   1.310 +  SetHasLockedStyleStates();
   1.311 +
   1.312 +  NotifyStyleStateChange(aStates);
   1.313 +}
   1.314 +
   1.315 +void
   1.316 +Element::UnlockStyleStates(EventStates aStates)
   1.317 +{
   1.318 +  EventStates* locks = new EventStates(LockedStyleStates());
   1.319 +
   1.320 +  *locks &= ~aStates;
   1.321 +
   1.322 +  if (locks->IsEmpty()) {
   1.323 +    DeleteProperty(nsGkAtoms::lockedStyleStates);
   1.324 +    ClearHasLockedStyleStates();
   1.325 +    delete locks;
   1.326 +  }
   1.327 +  else {
   1.328 +    SetProperty(nsGkAtoms::lockedStyleStates, locks,
   1.329 +                nsINode::DeleteProperty<EventStates>);
   1.330 +  }
   1.331 +
   1.332 +  NotifyStyleStateChange(aStates);
   1.333 +}
   1.334 +
   1.335 +void
   1.336 +Element::ClearStyleStateLocks()
   1.337 +{
   1.338 +  EventStates locks = LockedStyleStates();
   1.339 +
   1.340 +  DeleteProperty(nsGkAtoms::lockedStyleStates);
   1.341 +  ClearHasLockedStyleStates();
   1.342 +
   1.343 +  NotifyStyleStateChange(locks);
   1.344 +}
   1.345 +
   1.346 +bool
   1.347 +Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
   1.348 +{
   1.349 +  // If we have a frame the frame has already loaded the binding.  And
   1.350 +  // otherwise, don't do anything else here unless we're dealing with
   1.351 +  // XUL or an HTML element that may have a plugin-related overlay
   1.352 +  // (i.e. object, embed, or applet).
   1.353 +  bool isXULorPluginElement = (IsXUL() ||
   1.354 +                               IsHTML(nsGkAtoms::object) ||
   1.355 +                               IsHTML(nsGkAtoms::embed) ||
   1.356 +                               IsHTML(nsGkAtoms::applet));
   1.357 +  nsIPresShell *shell = aDocument->GetShell();
   1.358 +  if (!shell || GetPrimaryFrame() || !isXULorPluginElement) {
   1.359 +    *aResult = nullptr;
   1.360 +
   1.361 +    return true;
   1.362 +  }
   1.363 +
   1.364 +  // Get the computed -moz-binding directly from the style context
   1.365 +  nsPresContext *pctx = shell->GetPresContext();
   1.366 +  NS_ENSURE_TRUE(pctx, false);
   1.367 +
   1.368 +  nsRefPtr<nsStyleContext> sc = pctx->StyleSet()->ResolveStyleFor(this,
   1.369 +                                                                  nullptr);
   1.370 +  NS_ENSURE_TRUE(sc, false);
   1.371 +
   1.372 +  *aResult = sc->StyleDisplay()->mBinding;
   1.373 +
   1.374 +  return true;
   1.375 +}
   1.376 +
   1.377 +JSObject*
   1.378 +Element::WrapObject(JSContext *aCx)
   1.379 +{
   1.380 +  JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx));
   1.381 +  if (!obj) {
   1.382 +    return nullptr;
   1.383 +  }
   1.384 +
   1.385 +  // Custom element prototype swizzling.
   1.386 +  CustomElementData* data = GetCustomElementData();
   1.387 +  if (obj && data) {
   1.388 +    // If this is a registered custom element then fix the prototype.
   1.389 +    JSAutoCompartment ac(aCx, obj);
   1.390 +    nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
   1.391 +    JS::Rooted<JSObject*> prototype(aCx);
   1.392 +    document->GetCustomPrototype(NodeInfo()->NamespaceID(), data->mType, &prototype);
   1.393 +    if (prototype) {
   1.394 +      if (!JS_WrapObject(aCx, &prototype) || !JS_SetPrototype(aCx, obj, prototype)) {
   1.395 +        dom::Throw(aCx, NS_ERROR_FAILURE);
   1.396 +        return nullptr;
   1.397 +      }
   1.398 +    }
   1.399 +  }
   1.400 +
   1.401 +  nsIDocument* doc;
   1.402 +  if (HasFlag(NODE_FORCE_XBL_BINDINGS)) {
   1.403 +    doc = OwnerDoc();
   1.404 +  }
   1.405 +  else {
   1.406 +    doc = GetCurrentDoc();
   1.407 +  }
   1.408 +
   1.409 +  if (!doc) {
   1.410 +    // There's no baseclass that cares about this call so we just
   1.411 +    // return here.
   1.412 +    return obj;
   1.413 +  }
   1.414 +
   1.415 +  // We must ensure that the XBL Binding is installed before we hand
   1.416 +  // back this object.
   1.417 +
   1.418 +  if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) && GetXBLBinding()) {
   1.419 +    // There's already a binding for this element so nothing left to
   1.420 +    // be done here.
   1.421 +
   1.422 +    // In theory we could call ExecuteAttachedHandler here when it's safe to
   1.423 +    // run script if we also removed the binding from the PAQ queue, but that
   1.424 +    // seems like a scary change that would mosly just add more
   1.425 +    // inconsistencies.
   1.426 +    return obj;
   1.427 +  }
   1.428 +
   1.429 +  // Make sure the style context goes away _before_ we load the binding
   1.430 +  // since that can destroy the relevant presshell.
   1.431 +  mozilla::css::URLValue *bindingURL;
   1.432 +  bool ok = GetBindingURL(doc, &bindingURL);
   1.433 +  if (!ok) {
   1.434 +    dom::Throw(aCx, NS_ERROR_FAILURE);
   1.435 +    return nullptr;
   1.436 +  }
   1.437 +
   1.438 +  if (!bindingURL) {
   1.439 +    // No binding, nothing left to do here.
   1.440 +    return obj;
   1.441 +  }
   1.442 +
   1.443 +  nsCOMPtr<nsIURI> uri = bindingURL->GetURI();
   1.444 +  nsCOMPtr<nsIPrincipal> principal = bindingURL->mOriginPrincipal;
   1.445 +
   1.446 +  // We have a binding that must be installed.
   1.447 +  bool dummy;
   1.448 +
   1.449 +  nsXBLService* xblService = nsXBLService::GetInstance();
   1.450 +  if (!xblService) {
   1.451 +    dom::Throw(aCx, NS_ERROR_NOT_AVAILABLE);
   1.452 +    return nullptr;
   1.453 +  }
   1.454 +
   1.455 +  {
   1.456 +    // Make a scope so that ~nsRefPtr can GC before returning obj.
   1.457 +    nsRefPtr<nsXBLBinding> binding;
   1.458 +    xblService->LoadBindings(this, uri, principal, getter_AddRefs(binding), &dummy);
   1.459 +
   1.460 +    if (binding) {
   1.461 +      if (nsContentUtils::IsSafeToRunScript()) {
   1.462 +        binding->ExecuteAttachedHandler();
   1.463 +      }
   1.464 +      else {
   1.465 +        nsContentUtils::AddScriptRunner(
   1.466 +          NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
   1.467 +      }
   1.468 +    }
   1.469 +  }
   1.470 +
   1.471 +  return obj;
   1.472 +}
   1.473 +
   1.474 +nsDOMTokenList*
   1.475 +Element::GetClassList()
   1.476 +{
   1.477 +  Element::nsDOMSlots *slots = DOMSlots();
   1.478 +
   1.479 +  if (!slots->mClassList) {
   1.480 +    nsIAtom* classAttr = GetClassAttributeName();
   1.481 +    if (classAttr) {
   1.482 +      slots->mClassList = new nsDOMTokenList(this, classAttr);
   1.483 +    }
   1.484 +  }
   1.485 +
   1.486 +  return slots->mClassList;
   1.487 +}
   1.488 +
   1.489 +void
   1.490 +Element::GetClassList(nsISupports** aClassList)
   1.491 +{
   1.492 +  NS_IF_ADDREF(*aClassList = GetClassList());
   1.493 +}
   1.494 +
   1.495 +already_AddRefed<nsIHTMLCollection>
   1.496 +Element::GetElementsByTagName(const nsAString& aLocalName)
   1.497 +{
   1.498 +  return NS_GetContentList(this, kNameSpaceID_Unknown, aLocalName);
   1.499 +}
   1.500 +
   1.501 +void
   1.502 +Element::GetElementsByTagName(const nsAString& aLocalName,
   1.503 +                              nsIDOMHTMLCollection** aResult)
   1.504 +{
   1.505 +  *aResult = GetElementsByTagName(aLocalName).take();
   1.506 +}
   1.507 +
   1.508 +nsIFrame*
   1.509 +Element::GetStyledFrame()
   1.510 +{
   1.511 +  nsIFrame *frame = GetPrimaryFrame(Flush_Layout);
   1.512 +  return frame ? nsLayoutUtils::GetStyleFrame(frame) : nullptr;
   1.513 +}
   1.514 +
   1.515 +nsIScrollableFrame*
   1.516 +Element::GetScrollFrame(nsIFrame **aStyledFrame, bool aFlushLayout)
   1.517 +{
   1.518 +  // it isn't clear what to return for SVG nodes, so just return nothing
   1.519 +  if (IsSVG()) {
   1.520 +    if (aStyledFrame) {
   1.521 +      *aStyledFrame = nullptr;
   1.522 +    }
   1.523 +    return nullptr;
   1.524 +  }
   1.525 +
   1.526 +  // Inline version of GetStyledFrame to use Flush_None if needed.
   1.527 +  nsIFrame* frame = GetPrimaryFrame(aFlushLayout ? Flush_Layout : Flush_None);
   1.528 +  if (frame) {
   1.529 +    frame = nsLayoutUtils::GetStyleFrame(frame);
   1.530 +  }
   1.531 +
   1.532 +  if (aStyledFrame) {
   1.533 +    *aStyledFrame = frame;
   1.534 +  }
   1.535 +  if (!frame) {
   1.536 +    return nullptr;
   1.537 +  }
   1.538 +
   1.539 +  // menu frames implement GetScrollTargetFrame but we don't want
   1.540 +  // to use it here.  Similar for comboboxes.
   1.541 +  nsIAtom* type = frame->GetType();
   1.542 +  if (type != nsGkAtoms::menuFrame && type != nsGkAtoms::comboboxControlFrame) {
   1.543 +    nsIScrollableFrame *scrollFrame = frame->GetScrollTargetFrame();
   1.544 +    if (scrollFrame)
   1.545 +      return scrollFrame;
   1.546 +  }
   1.547 +
   1.548 +  nsIDocument* doc = OwnerDoc();
   1.549 +  bool quirksMode = doc->GetCompatibilityMode() == eCompatibility_NavQuirks;
   1.550 +  Element* elementWithRootScrollInfo =
   1.551 +    quirksMode ? doc->GetBodyElement() : doc->GetRootElement();
   1.552 +  if (this == elementWithRootScrollInfo) {
   1.553 +    // In quirks mode, the scroll info for the body element should map to the
   1.554 +    // root scrollable frame.
   1.555 +    // In strict mode, the scroll info for the root element should map to the
   1.556 +    // the root scrollable frame.
   1.557 +    return frame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
   1.558 +  }
   1.559 +
   1.560 +  return nullptr;
   1.561 +}
   1.562 +
   1.563 +void
   1.564 +Element::ScrollIntoView(bool aTop)
   1.565 +{
   1.566 +  nsIDocument *document = GetCurrentDoc();
   1.567 +  if (!document) {
   1.568 +    return;
   1.569 +  }
   1.570 +
   1.571 +  // Get the presentation shell
   1.572 +  nsCOMPtr<nsIPresShell> presShell = document->GetShell();
   1.573 +  if (!presShell) {
   1.574 +    return;
   1.575 +  }
   1.576 +
   1.577 +  int16_t vpercent = aTop ? nsIPresShell::SCROLL_TOP :
   1.578 +    nsIPresShell::SCROLL_BOTTOM;
   1.579 +
   1.580 +  presShell->ScrollContentIntoView(this,
   1.581 +                                   nsIPresShell::ScrollAxis(
   1.582 +                                     vpercent,
   1.583 +                                     nsIPresShell::SCROLL_ALWAYS),
   1.584 +                                   nsIPresShell::ScrollAxis(),
   1.585 +                                   nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
   1.586 +}
   1.587 +
   1.588 +bool
   1.589 +Element::ScrollByNoFlush(int32_t aDx, int32_t aDy)
   1.590 +{
   1.591 +  nsIScrollableFrame* sf = GetScrollFrame(nullptr, false);
   1.592 +  if (!sf) {
   1.593 +    return false;
   1.594 +  }
   1.595 +
   1.596 +  nsWeakFrame weakRef(sf->GetScrolledFrame());
   1.597 +
   1.598 +  CSSIntPoint before = sf->GetScrollPositionCSSPixels();
   1.599 +  sf->ScrollToCSSPixelsApproximate(CSSIntPoint(before.x + aDx, before.y + aDy));
   1.600 +
   1.601 +  // The frame was destroyed, can't keep on scrolling.
   1.602 +  if (!weakRef.IsAlive()) {
   1.603 +    return false;
   1.604 +  }
   1.605 +
   1.606 +  CSSIntPoint after = sf->GetScrollPositionCSSPixels();
   1.607 +  return (before != after);
   1.608 +}
   1.609 +
   1.610 +static nsSize GetScrollRectSizeForOverflowVisibleFrame(nsIFrame* aFrame)
   1.611 +{
   1.612 +  if (!aFrame) {
   1.613 +    return nsSize(0,0);
   1.614 +  }
   1.615 +
   1.616 +  nsRect paddingRect = aFrame->GetPaddingRectRelativeToSelf();
   1.617 +  nsOverflowAreas overflowAreas(paddingRect, paddingRect);
   1.618 +  // Add the scrollable overflow areas of children (if any) to the paddingRect.
   1.619 +  // It's important to start with the paddingRect, otherwise if there are no
   1.620 +  // children the overflow rect will be 0,0,0,0 which will force the point 0,0
   1.621 +  // to be included in the final rect.
   1.622 +  nsLayoutUtils::UnionChildOverflow(aFrame, overflowAreas);
   1.623 +  // Make sure that an empty padding-rect's edges are included, by adding
   1.624 +  // the padding-rect in again with UnionEdges.
   1.625 +  nsRect overflowRect =
   1.626 +    overflowAreas.ScrollableOverflow().UnionEdges(paddingRect);
   1.627 +  return nsLayoutUtils::GetScrolledRect(aFrame,
   1.628 +      overflowRect, paddingRect.Size(),
   1.629 +      aFrame->StyleVisibility()->mDirection).Size();
   1.630 +}
   1.631 +
   1.632 +int32_t
   1.633 +Element::ScrollHeight()
   1.634 +{
   1.635 +  if (IsSVG())
   1.636 +    return 0;
   1.637 +
   1.638 +  nsIScrollableFrame* sf = GetScrollFrame();
   1.639 +  nscoord height;
   1.640 +  if (sf) {
   1.641 +    height = sf->GetScrollRange().height + sf->GetScrollPortRect().height;
   1.642 +  } else {
   1.643 +    height = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).height;
   1.644 +  }
   1.645 +
   1.646 +  return nsPresContext::AppUnitsToIntCSSPixels(height);
   1.647 +}
   1.648 +
   1.649 +int32_t
   1.650 +Element::ScrollWidth()
   1.651 +{
   1.652 +  if (IsSVG())
   1.653 +    return 0;
   1.654 +
   1.655 +  nsIScrollableFrame* sf = GetScrollFrame();
   1.656 +  nscoord width;
   1.657 +  if (sf) {
   1.658 +    width = sf->GetScrollRange().width + sf->GetScrollPortRect().width;
   1.659 +  } else {
   1.660 +    width = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).width;
   1.661 +  }
   1.662 +
   1.663 +  return nsPresContext::AppUnitsToIntCSSPixels(width);
   1.664 +}
   1.665 +
   1.666 +nsRect
   1.667 +Element::GetClientAreaRect()
   1.668 +{
   1.669 +  nsIFrame* styledFrame;
   1.670 +  nsIScrollableFrame* sf = GetScrollFrame(&styledFrame);
   1.671 +
   1.672 +  if (sf) {
   1.673 +    return sf->GetScrollPortRect();
   1.674 +  }
   1.675 +
   1.676 +  if (styledFrame &&
   1.677 +      (styledFrame->StyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE ||
   1.678 +       styledFrame->IsFrameOfType(nsIFrame::eReplaced))) {
   1.679 +    // Special case code to make client area work even when there isn't
   1.680 +    // a scroll view, see bug 180552, bug 227567.
   1.681 +    return styledFrame->GetPaddingRect() - styledFrame->GetPositionIgnoringScrolling();
   1.682 +  }
   1.683 +
   1.684 +  // SVG nodes reach here and just return 0
   1.685 +  return nsRect(0, 0, 0, 0);
   1.686 +}
   1.687 +
   1.688 +already_AddRefed<DOMRect>
   1.689 +Element::GetBoundingClientRect()
   1.690 +{
   1.691 +  nsRefPtr<DOMRect> rect = new DOMRect(this);
   1.692 +  
   1.693 +  nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
   1.694 +  if (!frame) {
   1.695 +    // display:none, perhaps? Return the empty rect
   1.696 +    return rect.forget();
   1.697 +  }
   1.698 +
   1.699 +  nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame,
   1.700 +          nsLayoutUtils::GetContainingBlockForClientRect(frame),
   1.701 +          nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
   1.702 +  rect->SetLayoutRect(r);
   1.703 +  return rect.forget();
   1.704 +}
   1.705 +
   1.706 +already_AddRefed<DOMRectList>
   1.707 +Element::GetClientRects()
   1.708 +{
   1.709 +  nsRefPtr<DOMRectList> rectList = new DOMRectList(this);
   1.710 +
   1.711 +  nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
   1.712 +  if (!frame) {
   1.713 +    // display:none, perhaps? Return an empty list
   1.714 +    return rectList.forget();
   1.715 +  }
   1.716 +
   1.717 +  nsLayoutUtils::RectListBuilder builder(rectList);
   1.718 +  nsLayoutUtils::GetAllInFlowRects(frame,
   1.719 +          nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder,
   1.720 +          nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
   1.721 +  return rectList.forget();
   1.722 +}
   1.723 +
   1.724 +
   1.725 +//----------------------------------------------------------------------
   1.726 +
   1.727 +void
   1.728 +Element::AddToIdTable(nsIAtom* aId)
   1.729 +{
   1.730 +  NS_ASSERTION(HasID(), "Node doesn't have an ID?");
   1.731 +  if (HasFlag(NODE_IS_IN_SHADOW_TREE)) {
   1.732 +    ShadowRoot* containingShadow = GetContainingShadow();
   1.733 +    containingShadow->AddToIdTable(this, aId);
   1.734 +  } else {
   1.735 +    nsIDocument* doc = GetCurrentDoc();
   1.736 +    if (doc && (!IsInAnonymousSubtree() || doc->IsXUL())) {
   1.737 +      doc->AddToIdTable(this, aId);
   1.738 +    }
   1.739 +  }
   1.740 +}
   1.741 +
   1.742 +void
   1.743 +Element::RemoveFromIdTable()
   1.744 +{
   1.745 +  if (HasID()) {
   1.746 +    RemoveFromIdTable(DoGetID());
   1.747 +  }
   1.748 +}
   1.749 +
   1.750 +void
   1.751 +Element::RemoveFromIdTable(nsIAtom* aId)
   1.752 +{
   1.753 +  NS_ASSERTION(HasID(), "Node doesn't have an ID?");
   1.754 +  if (HasFlag(NODE_IS_IN_SHADOW_TREE)) {
   1.755 +    ShadowRoot* containingShadow = GetContainingShadow();
   1.756 +    // Check for containingShadow because it may have
   1.757 +    // been deleted during unlinking.
   1.758 +    if (containingShadow) {
   1.759 +      containingShadow->RemoveFromIdTable(this, aId);
   1.760 +    }
   1.761 +  } else {
   1.762 +    nsIDocument* doc = GetCurrentDoc();
   1.763 +    if (doc && (!IsInAnonymousSubtree() || doc->IsXUL())) {
   1.764 +      // id can be null during mutation events evilness. Also, XUL elements
   1.765 +      // loose their proto attributes during cc-unlink, so this can happen
   1.766 +      // during cc-unlink too.
   1.767 +      if (aId) {
   1.768 +        doc->RemoveFromIdTable(this, aId);
   1.769 +      }
   1.770 +    }
   1.771 +  }
   1.772 +}
   1.773 +
   1.774 +already_AddRefed<ShadowRoot>
   1.775 +Element::CreateShadowRoot(ErrorResult& aError)
   1.776 +{
   1.777 +  nsAutoScriptBlocker scriptBlocker;
   1.778 +
   1.779 +  nsCOMPtr<nsINodeInfo> nodeInfo;
   1.780 +  nodeInfo = mNodeInfo->NodeInfoManager()->GetNodeInfo(
   1.781 +    nsGkAtoms::documentFragmentNodeName, nullptr, kNameSpaceID_None,
   1.782 +    nsIDOMNode::DOCUMENT_FRAGMENT_NODE);
   1.783 +
   1.784 +  nsRefPtr<nsXBLDocumentInfo> docInfo = new nsXBLDocumentInfo(OwnerDoc());
   1.785 +
   1.786 +  nsXBLPrototypeBinding* protoBinding = new nsXBLPrototypeBinding();
   1.787 +  aError = protoBinding->Init(NS_LITERAL_CSTRING("shadowroot"),
   1.788 +                              docInfo, this, true);
   1.789 +  if (aError.Failed()) {
   1.790 +    delete protoBinding;
   1.791 +    return nullptr;
   1.792 +  }
   1.793 +
   1.794 +  // Unlike for XBL, false is the default for inheriting style.
   1.795 +  protoBinding->SetInheritsStyle(false);
   1.796 +
   1.797 +  // Calling SetPrototypeBinding takes ownership of protoBinding.
   1.798 +  docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
   1.799 +
   1.800 +  nsRefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
   1.801 +                                                   protoBinding);
   1.802 +
   1.803 +  // Replace the old ShadowRoot with the new one and let the old
   1.804 +  // ShadowRoot know about the younger ShadowRoot because the old
   1.805 +  // ShadowRoot is projected into the younger ShadowRoot's shadow
   1.806 +  // insertion point (if it exists).
   1.807 +  ShadowRoot* olderShadow = GetShadowRoot();
   1.808 +  SetShadowRoot(shadowRoot);
   1.809 +  if (olderShadow) {
   1.810 +    olderShadow->SetYoungerShadow(shadowRoot);
   1.811 +  }
   1.812 +
   1.813 +  // xblBinding takes ownership of docInfo.
   1.814 +  nsRefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);
   1.815 +  shadowRoot->SetAssociatedBinding(xblBinding);
   1.816 +  xblBinding->SetBoundElement(this);
   1.817 +
   1.818 +  SetXBLBinding(xblBinding);
   1.819 +
   1.820 +  // Recreate the frame for the bound content because binding a ShadowRoot
   1.821 +  // changes how things are rendered.
   1.822 +  nsIDocument* doc = GetCurrentDoc();
   1.823 +  if (doc) {
   1.824 +    nsIPresShell *shell = doc->GetShell();
   1.825 +    if (shell) {
   1.826 +      shell->RecreateFramesFor(this);
   1.827 +    }
   1.828 +  }
   1.829 +
   1.830 +  return shadowRoot.forget();
   1.831 +}
   1.832 +
   1.833 +void
   1.834 +Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
   1.835 +{
   1.836 +  const nsAttrValue* val =
   1.837 +    mAttrsAndChildren.GetAttr(aName,
   1.838 +                              IsHTML() && IsInHTMLDocument() ?
   1.839 +                                eIgnoreCase : eCaseMatters);
   1.840 +  if (val) {
   1.841 +    val->ToString(aReturn);
   1.842 +  } else {
   1.843 +    if (IsXUL()) {
   1.844 +      // XXX should be SetDOMStringToNull(aReturn);
   1.845 +      // See bug 232598
   1.846 +      // aReturn is already empty
   1.847 +    } else {
   1.848 +      aReturn.SetNull();
   1.849 +    }
   1.850 +  }
   1.851 +}
   1.852 +
   1.853 +void
   1.854 +Element::SetAttribute(const nsAString& aName,
   1.855 +                      const nsAString& aValue,
   1.856 +                      ErrorResult& aError)
   1.857 +{
   1.858 +  const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
   1.859 +
   1.860 +  if (!name) {
   1.861 +    aError = nsContentUtils::CheckQName(aName, false);
   1.862 +    if (aError.Failed()) {
   1.863 +      return;
   1.864 +    }
   1.865 +
   1.866 +    nsCOMPtr<nsIAtom> nameAtom;
   1.867 +    if (IsHTML() && IsInHTMLDocument()) {
   1.868 +      nsAutoString lower;
   1.869 +      nsresult rv = nsContentUtils::ASCIIToLower(aName, lower);
   1.870 +      if (NS_SUCCEEDED(rv)) {
   1.871 +        nameAtom = do_GetAtom(lower);
   1.872 +      }
   1.873 +    }
   1.874 +    else {
   1.875 +      nameAtom = do_GetAtom(aName);
   1.876 +    }
   1.877 +    if (!nameAtom) {
   1.878 +      aError.Throw(NS_ERROR_OUT_OF_MEMORY);
   1.879 +      return;
   1.880 +    }
   1.881 +    aError = SetAttr(kNameSpaceID_None, nameAtom, aValue, true);
   1.882 +    return;
   1.883 +  }
   1.884 +
   1.885 +  aError = SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
   1.886 +                   aValue, true);
   1.887 +  return;
   1.888 +}
   1.889 +
   1.890 +void
   1.891 +Element::RemoveAttribute(const nsAString& aName, ErrorResult& aError)
   1.892 +{
   1.893 +  const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
   1.894 +
   1.895 +  if (!name) {
   1.896 +    // If there is no canonical nsAttrName for this attribute name, then the
   1.897 +    // attribute does not exist and we can't get its namespace ID and
   1.898 +    // local name below, so we return early.
   1.899 +    return;
   1.900 +  }
   1.901 +
   1.902 +  // Hold a strong reference here so that the atom or nodeinfo doesn't go
   1.903 +  // away during UnsetAttr. If it did UnsetAttr would be left with a
   1.904 +  // dangling pointer as argument without knowing it.
   1.905 +  nsAttrName tmp(*name);
   1.906 +
   1.907 +  aError = UnsetAttr(name->NamespaceID(), name->LocalName(), true);
   1.908 +}
   1.909 +
   1.910 +Attr*
   1.911 +Element::GetAttributeNode(const nsAString& aName)
   1.912 +{
   1.913 +  OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNode);
   1.914 +  return Attributes()->GetNamedItem(aName);
   1.915 +}
   1.916 +
   1.917 +already_AddRefed<Attr>
   1.918 +Element::SetAttributeNode(Attr& aNewAttr, ErrorResult& aError)
   1.919 +{
   1.920 +  OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNode);
   1.921 +
   1.922 +  return Attributes()->SetNamedItem(aNewAttr, aError);
   1.923 +}
   1.924 +
   1.925 +already_AddRefed<Attr>
   1.926 +Element::RemoveAttributeNode(Attr& aAttribute,
   1.927 +                             ErrorResult& aError)
   1.928 +{
   1.929 +  OwnerDoc()->WarnOnceAbout(nsIDocument::eRemoveAttributeNode);
   1.930 +  return Attributes()->RemoveNamedItem(aAttribute.NodeName(), aError);
   1.931 +}
   1.932 +
   1.933 +void
   1.934 +Element::GetAttributeNS(const nsAString& aNamespaceURI,
   1.935 +                        const nsAString& aLocalName,
   1.936 +                        nsAString& aReturn)
   1.937 +{
   1.938 +  int32_t nsid =
   1.939 +    nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
   1.940 +
   1.941 +  if (nsid == kNameSpaceID_Unknown) {
   1.942 +    // Unknown namespace means no attribute.
   1.943 +    SetDOMStringToNull(aReturn);
   1.944 +    return;
   1.945 +  }
   1.946 +
   1.947 +  nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
   1.948 +  bool hasAttr = GetAttr(nsid, name, aReturn);
   1.949 +  if (!hasAttr) {
   1.950 +    SetDOMStringToNull(aReturn);
   1.951 +  }
   1.952 +}
   1.953 +
   1.954 +void
   1.955 +Element::SetAttributeNS(const nsAString& aNamespaceURI,
   1.956 +                        const nsAString& aQualifiedName,
   1.957 +                        const nsAString& aValue,
   1.958 +                        ErrorResult& aError)
   1.959 +{
   1.960 +  nsCOMPtr<nsINodeInfo> ni;
   1.961 +  aError =
   1.962 +    nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, aQualifiedName,
   1.963 +                                         mNodeInfo->NodeInfoManager(),
   1.964 +                                         nsIDOMNode::ATTRIBUTE_NODE,
   1.965 +                                         getter_AddRefs(ni));
   1.966 +  if (aError.Failed()) {
   1.967 +    return;
   1.968 +  }
   1.969 +
   1.970 +  aError = SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(),
   1.971 +                   aValue, true);
   1.972 +}
   1.973 +
   1.974 +void
   1.975 +Element::RemoveAttributeNS(const nsAString& aNamespaceURI,
   1.976 +                           const nsAString& aLocalName,
   1.977 +                           ErrorResult& aError)
   1.978 +{
   1.979 +  nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
   1.980 +  int32_t nsid =
   1.981 +    nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
   1.982 +
   1.983 +  if (nsid == kNameSpaceID_Unknown) {
   1.984 +    // If the namespace ID is unknown, it means there can't possibly be an
   1.985 +    // existing attribute. We would need a known namespace ID to pass into
   1.986 +    // UnsetAttr, so we return early if we don't have one.
   1.987 +    return;
   1.988 +  }
   1.989 +
   1.990 +  aError = UnsetAttr(nsid, name, true);
   1.991 +}
   1.992 +
   1.993 +Attr*
   1.994 +Element::GetAttributeNodeNS(const nsAString& aNamespaceURI,
   1.995 +                            const nsAString& aLocalName)
   1.996 +{
   1.997 +  OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNodeNS);
   1.998 +
   1.999 +  return GetAttributeNodeNSInternal(aNamespaceURI, aLocalName);
  1.1000 +}
  1.1001 +
  1.1002 +Attr*
  1.1003 +Element::GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
  1.1004 +                                    const nsAString& aLocalName)
  1.1005 +{
  1.1006 +  return Attributes()->GetNamedItemNS(aNamespaceURI, aLocalName);
  1.1007 +}
  1.1008 +
  1.1009 +already_AddRefed<Attr>
  1.1010 +Element::SetAttributeNodeNS(Attr& aNewAttr,
  1.1011 +                            ErrorResult& aError)
  1.1012 +{
  1.1013 +  OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNodeNS);
  1.1014 +  return Attributes()->SetNamedItemNS(aNewAttr, aError);
  1.1015 +}
  1.1016 +
  1.1017 +already_AddRefed<nsIHTMLCollection>
  1.1018 +Element::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
  1.1019 +                                const nsAString& aLocalName,
  1.1020 +                                ErrorResult& aError)
  1.1021 +{
  1.1022 +  int32_t nameSpaceId = kNameSpaceID_Wildcard;
  1.1023 +
  1.1024 +  if (!aNamespaceURI.EqualsLiteral("*")) {
  1.1025 +    aError =
  1.1026 +      nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
  1.1027 +                                                            nameSpaceId);
  1.1028 +    if (aError.Failed()) {
  1.1029 +      return nullptr;
  1.1030 +    }
  1.1031 +  }
  1.1032 +
  1.1033 +  NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
  1.1034 +
  1.1035 +  return NS_GetContentList(this, nameSpaceId, aLocalName);
  1.1036 +}
  1.1037 +
  1.1038 +nsresult
  1.1039 +Element::GetElementsByTagNameNS(const nsAString& namespaceURI,
  1.1040 +                                const nsAString& localName,
  1.1041 +                                nsIDOMHTMLCollection** aResult)
  1.1042 +{
  1.1043 +  mozilla::ErrorResult rv;
  1.1044 +  nsCOMPtr<nsIHTMLCollection> list =
  1.1045 +    GetElementsByTagNameNS(namespaceURI, localName, rv);
  1.1046 +  if (rv.Failed()) {
  1.1047 +    return rv.ErrorCode();
  1.1048 +  }
  1.1049 +  list.forget(aResult);
  1.1050 +  return NS_OK;
  1.1051 +}
  1.1052 +
  1.1053 +bool
  1.1054 +Element::HasAttributeNS(const nsAString& aNamespaceURI,
  1.1055 +                        const nsAString& aLocalName) const
  1.1056 +{
  1.1057 +  int32_t nsid =
  1.1058 +    nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
  1.1059 +
  1.1060 +  if (nsid == kNameSpaceID_Unknown) {
  1.1061 +    // Unknown namespace means no attr...
  1.1062 +    return false;
  1.1063 +  }
  1.1064 +
  1.1065 +  nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
  1.1066 +  return HasAttr(nsid, name);
  1.1067 +}
  1.1068 +
  1.1069 +already_AddRefed<nsIHTMLCollection>
  1.1070 +Element::GetElementsByClassName(const nsAString& aClassNames)
  1.1071 +{
  1.1072 +  return nsContentUtils::GetElementsByClassName(this, aClassNames);
  1.1073 +}
  1.1074 +
  1.1075 +nsresult
  1.1076 +Element::GetElementsByClassName(const nsAString& aClassNames,
  1.1077 +                                nsIDOMHTMLCollection** aResult)
  1.1078 +{
  1.1079 +  *aResult =
  1.1080 +    nsContentUtils::GetElementsByClassName(this, aClassNames).take();
  1.1081 +  return NS_OK;
  1.1082 +}
  1.1083 +
  1.1084 +nsresult
  1.1085 +Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
  1.1086 +                    nsIContent* aBindingParent,
  1.1087 +                    bool aCompileEventHandlers)
  1.1088 +{
  1.1089 +  NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
  1.1090 +  NS_PRECONDITION((NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc()),
  1.1091 +                  "Must have the same owner document");
  1.1092 +  NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
  1.1093 +                  "aDocument must be current doc of aParent");
  1.1094 +  NS_PRECONDITION(!GetCurrentDoc(), "Already have a document.  Unbind first!");
  1.1095 +  // Note that as we recurse into the kids, they'll have a non-null parent.  So
  1.1096 +  // only assert if our parent is _changing_ while we have a parent.
  1.1097 +  NS_PRECONDITION(!GetParent() || aParent == GetParent(),
  1.1098 +                  "Already have a parent.  Unbind first!");
  1.1099 +  NS_PRECONDITION(!GetBindingParent() ||
  1.1100 +                  aBindingParent == GetBindingParent() ||
  1.1101 +                  (!aBindingParent && aParent &&
  1.1102 +                   aParent->GetBindingParent() == GetBindingParent()),
  1.1103 +                  "Already have a binding parent.  Unbind first!");
  1.1104 +  NS_PRECONDITION(!aParent || !aDocument ||
  1.1105 +                  !aParent->HasFlag(NODE_FORCE_XBL_BINDINGS),
  1.1106 +                  "Parent in document but flagged as forcing XBL");
  1.1107 +  NS_PRECONDITION(aBindingParent != this,
  1.1108 +                  "Content must not be its own binding parent");
  1.1109 +  NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
  1.1110 +                  aBindingParent == aParent,
  1.1111 +                  "Native anonymous content must have its parent as its "
  1.1112 +                  "own binding parent");
  1.1113 +  NS_PRECONDITION(aBindingParent || !aParent ||
  1.1114 +                  aBindingParent == aParent->GetBindingParent(),
  1.1115 +                  "We should be passed the right binding parent");
  1.1116 +
  1.1117 +#ifdef MOZ_XUL
  1.1118 +  // First set the binding parent
  1.1119 +  nsXULElement* xulElem = nsXULElement::FromContent(this);
  1.1120 +  if (xulElem) {
  1.1121 +    xulElem->SetXULBindingParent(aBindingParent);
  1.1122 +  }
  1.1123 +  else 
  1.1124 +#endif
  1.1125 +  {
  1.1126 +    if (aBindingParent) {
  1.1127 +      nsDOMSlots *slots = DOMSlots();
  1.1128 +
  1.1129 +      slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
  1.1130 +    }
  1.1131 +  }
  1.1132 +  NS_ASSERTION(!aBindingParent || IsRootOfNativeAnonymousSubtree() ||
  1.1133 +               !HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) ||
  1.1134 +               (aParent && aParent->IsInNativeAnonymousSubtree()),
  1.1135 +               "Trying to re-bind content from native anonymous subtree to "
  1.1136 +               "non-native anonymous parent!");
  1.1137 +  if (aParent) {
  1.1138 +    if (aParent->IsInNativeAnonymousSubtree()) {
  1.1139 +      SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
  1.1140 +    }
  1.1141 +    if (aParent->HasFlag(NODE_CHROME_ONLY_ACCESS)) {
  1.1142 +      SetFlags(NODE_CHROME_ONLY_ACCESS);
  1.1143 +    }
  1.1144 +    if (aParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
  1.1145 +      SetFlags(NODE_IS_IN_SHADOW_TREE);
  1.1146 +    }
  1.1147 +    ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
  1.1148 +    if (parentContainingShadow) {
  1.1149 +      DOMSlots()->mContainingShadow = parentContainingShadow;
  1.1150 +    }
  1.1151 +  }
  1.1152 +
  1.1153 +  bool hadForceXBL = HasFlag(NODE_FORCE_XBL_BINDINGS);
  1.1154 +
  1.1155 +  // Now set the parent and set the "Force attach xbl" flag if needed.
  1.1156 +  if (aParent) {
  1.1157 +    if (!GetParent()) {
  1.1158 +      NS_ADDREF(aParent);
  1.1159 +    }
  1.1160 +    mParent = aParent;
  1.1161 +
  1.1162 +    if (aParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
  1.1163 +      SetFlags(NODE_FORCE_XBL_BINDINGS);
  1.1164 +    }
  1.1165 +  }
  1.1166 +  else {
  1.1167 +    mParent = aDocument;
  1.1168 +  }
  1.1169 +  SetParentIsContent(aParent);
  1.1170 +
  1.1171 +  // XXXbz sXBL/XBL2 issue!
  1.1172 +
  1.1173 +  // Finally, set the document
  1.1174 +  if (aDocument) {
  1.1175 +    // Notify XBL- & nsIAnonymousContentCreator-generated
  1.1176 +    // anonymous content that the document is changing.
  1.1177 +    // XXXbz ordering issues here?  Probably not, since ChangeDocumentFor is
  1.1178 +    // just pretty broken anyway....  Need to get it working.
  1.1179 +    // XXXbz XBL doesn't handle this (asserts), and we don't really want
  1.1180 +    // to be doing this during parsing anyway... sort this out.    
  1.1181 +    //    aDocument->BindingManager()->ChangeDocumentFor(this, nullptr,
  1.1182 +    //                                                   aDocument);
  1.1183 +
  1.1184 +    // We no longer need to track the subtree pointer (and in fact we'll assert
  1.1185 +    // if we do this any later).
  1.1186 +    ClearSubtreeRootPointer();
  1.1187 +
  1.1188 +    // Being added to a document.
  1.1189 +    SetInDocument();
  1.1190 +
  1.1191 +    if (GetCustomElementData()) {
  1.1192 +      // Enqueue an attached callback for the custom element.
  1.1193 +      aDocument->EnqueueLifecycleCallback(nsIDocument::eAttached, this);
  1.1194 +    }
  1.1195 +
  1.1196 +    // Unset this flag since we now really are in a document.
  1.1197 +    UnsetFlags(NODE_FORCE_XBL_BINDINGS |
  1.1198 +               // And clear the lazy frame construction bits.
  1.1199 +               NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
  1.1200 +               // And the restyle bits
  1.1201 +               ELEMENT_ALL_RESTYLE_FLAGS);
  1.1202 +
  1.1203 +    // Propagate scoped style sheet tracking bit.
  1.1204 +    SetIsElementInStyleScope(mParent->IsElementInStyleScope());
  1.1205 +  } else {
  1.1206 +    // If we're not in the doc, update our subtree pointer.
  1.1207 +    SetSubtreeRootPointer(aParent->SubtreeRoot());
  1.1208 +  }
  1.1209 +
  1.1210 +  // This has to be here, rather than in nsGenericHTMLElement::BindToTree,
  1.1211 +  //  because it has to happen after updating the parent pointer, but before
  1.1212 +  //  recursively binding the kids.
  1.1213 +  if (IsHTML()) {
  1.1214 +    SetDirOnBind(this, aParent);
  1.1215 +  }
  1.1216 +
  1.1217 +  // If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
  1.1218 +  // that also need to be told that they are moving.
  1.1219 +  nsresult rv;
  1.1220 +  if (hadForceXBL) {
  1.1221 +    nsBindingManager* bmgr = OwnerDoc()->BindingManager();
  1.1222 +
  1.1223 +    nsXBLBinding* contBinding = bmgr->GetBindingWithContent(this);
  1.1224 +    // First check if we have a binding...
  1.1225 +    if (contBinding) {
  1.1226 +      nsCOMPtr<nsIContent> anonRoot = contBinding->GetAnonymousContent();
  1.1227 +      bool allowScripts = contBinding->AllowScripts();
  1.1228 +      for (nsCOMPtr<nsIContent> child = anonRoot->GetFirstChild();
  1.1229 +           child;
  1.1230 +           child = child->GetNextSibling()) {
  1.1231 +        rv = child->BindToTree(aDocument, this, this, allowScripts);
  1.1232 +        NS_ENSURE_SUCCESS(rv, rv);
  1.1233 +      }
  1.1234 +    }
  1.1235 +  }
  1.1236 +
  1.1237 +  UpdateEditableState(false);
  1.1238 +
  1.1239 +  // Now recurse into our kids
  1.1240 +  for (nsIContent* child = GetFirstChild(); child;
  1.1241 +       child = child->GetNextSibling()) {
  1.1242 +    rv = child->BindToTree(aDocument, this, aBindingParent,
  1.1243 +                           aCompileEventHandlers);
  1.1244 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1245 +  }
  1.1246 +
  1.1247 +  nsNodeUtils::ParentChainChanged(this);
  1.1248 +
  1.1249 +  if (HasID()) {
  1.1250 +    AddToIdTable(DoGetID());
  1.1251 +  }
  1.1252 +
  1.1253 +  if (MayHaveStyle() && !IsXUL()) {
  1.1254 +    // XXXbz if we already have a style attr parsed, this won't do
  1.1255 +    // anything... need to fix that.
  1.1256 +    // If MayHaveStyle() is true, we must be an nsStyledElement
  1.1257 +    static_cast<nsStyledElement*>(this)->ReparseStyleAttribute(false);
  1.1258 +  }
  1.1259 +
  1.1260 +  if (aDocument) {
  1.1261 +    // If we're in a document now, let our mapped attrs know what their new
  1.1262 +    // sheet is.  This is safe to run for non-mapped-attribute elements too;
  1.1263 +    // it'll just do a small bit of unnecessary work.  But most elements in
  1.1264 +    // practice are mapped-attribute elements.
  1.1265 +    nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
  1.1266 +    if (sheet) {
  1.1267 +      mAttrsAndChildren.SetMappedAttrStyleSheet(sheet);
  1.1268 +    }
  1.1269 +  }
  1.1270 +
  1.1271 +  // XXXbz script execution during binding can trigger some of these
  1.1272 +  // postcondition asserts....  But we do want that, since things will
  1.1273 +  // generally be quite broken when that happens.
  1.1274 +  NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
  1.1275 +  NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
  1.1276 +  NS_POSTCONDITION(aBindingParent == GetBindingParent(),
  1.1277 +                   "Bound to wrong binding parent");
  1.1278 +
  1.1279 +  return NS_OK;
  1.1280 +}
  1.1281 +
  1.1282 +class RemoveFromBindingManagerRunnable : public nsRunnable {
  1.1283 +public:
  1.1284 +  RemoveFromBindingManagerRunnable(nsBindingManager* aManager,
  1.1285 +                                   Element* aElement,
  1.1286 +                                   nsIDocument* aDoc):
  1.1287 +    mManager(aManager), mElement(aElement), mDoc(aDoc)
  1.1288 +  {}
  1.1289 +
  1.1290 +  NS_IMETHOD Run()
  1.1291 +  {
  1.1292 +    // It may be the case that the element was removed from the
  1.1293 +    // DOM, causing this runnable to be created, then inserted back
  1.1294 +    // into the document before the this runnable had a chance to
  1.1295 +    // tear down the binding. Only tear down the binding if the element
  1.1296 +    // is still no longer in the DOM. nsXBLService::LoadBinding tears
  1.1297 +    // down the old binding if the element is inserted back into the
  1.1298 +    // DOM and loads a different binding.
  1.1299 +    if (!mElement->IsInDoc()) {
  1.1300 +      mManager->RemovedFromDocumentInternal(mElement, mDoc);
  1.1301 +    }
  1.1302 +
  1.1303 +    return NS_OK;
  1.1304 +  }
  1.1305 +
  1.1306 +private:
  1.1307 +  nsRefPtr<nsBindingManager> mManager;
  1.1308 +  nsRefPtr<Element> mElement;
  1.1309 +  nsCOMPtr<nsIDocument> mDoc;
  1.1310 +};
  1.1311 +
  1.1312 +void
  1.1313 +Element::UnbindFromTree(bool aDeep, bool aNullParent)
  1.1314 +{
  1.1315 +  NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
  1.1316 +                  "Shallow unbind won't clear document and binding parent on "
  1.1317 +                  "kids!");
  1.1318 +
  1.1319 +  RemoveFromIdTable();
  1.1320 +
  1.1321 +  // Make sure to unbind this node before doing the kids
  1.1322 +  nsIDocument *document =
  1.1323 +    HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetCurrentDoc();
  1.1324 +
  1.1325 +  if (aNullParent) {
  1.1326 +    if (IsFullScreenAncestor()) {
  1.1327 +      // The element being removed is an ancestor of the full-screen element,
  1.1328 +      // exit full-screen state.
  1.1329 +      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
  1.1330 +                                      NS_LITERAL_CSTRING("DOM"), OwnerDoc(),
  1.1331 +                                      nsContentUtils::eDOM_PROPERTIES,
  1.1332 +                                      "RemovedFullScreenElement");
  1.1333 +      // Fully exit full-screen.
  1.1334 +      nsIDocument::ExitFullscreen(OwnerDoc(), /* async */ false);
  1.1335 +    }
  1.1336 +    if (HasPointerLock()) {
  1.1337 +      nsIDocument::UnlockPointer();
  1.1338 +    }
  1.1339 +    if (GetParent()) {
  1.1340 +      nsINode* p = mParent;
  1.1341 +      mParent = nullptr;
  1.1342 +      NS_RELEASE(p);
  1.1343 +    } else {
  1.1344 +      mParent = nullptr;
  1.1345 +    }
  1.1346 +    SetParentIsContent(false);
  1.1347 +  }
  1.1348 +  ClearInDocument();
  1.1349 +
  1.1350 +  // Begin keeping track of our subtree root.
  1.1351 +  SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
  1.1352 +
  1.1353 +  if (document) {
  1.1354 +    // Notify XBL- & nsIAnonymousContentCreator-generated
  1.1355 +    // anonymous content that the document is changing.
  1.1356 +    if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
  1.1357 +      nsContentUtils::AddScriptRunner(
  1.1358 +        new RemoveFromBindingManagerRunnable(document->BindingManager(), this,
  1.1359 +                                             document));
  1.1360 +    }
  1.1361 +
  1.1362 +    document->ClearBoxObjectFor(this);
  1.1363 +
  1.1364 +    if (GetCustomElementData()) {
  1.1365 +      // Enqueue a detached callback for the custom element.
  1.1366 +      document->EnqueueLifecycleCallback(nsIDocument::eDetached, this);
  1.1367 +    }
  1.1368 +  }
  1.1369 +
  1.1370 +  // Ensure that CSS transitions don't continue on an element at a
  1.1371 +  // different place in the tree (even if reinserted before next
  1.1372 +  // animation refresh).
  1.1373 +  // FIXME (Bug 522599): Need a test for this.
  1.1374 +  if (HasFlag(NODE_HAS_PROPERTIES)) {
  1.1375 +    DeleteProperty(nsGkAtoms::transitionsOfBeforeProperty);
  1.1376 +    DeleteProperty(nsGkAtoms::transitionsOfAfterProperty);
  1.1377 +    DeleteProperty(nsGkAtoms::transitionsProperty);
  1.1378 +    DeleteProperty(nsGkAtoms::animationsOfBeforeProperty);
  1.1379 +    DeleteProperty(nsGkAtoms::animationsOfAfterProperty);
  1.1380 +    DeleteProperty(nsGkAtoms::animationsProperty);
  1.1381 +  }
  1.1382 +
  1.1383 +  // Unset this since that's what the old code effectively did.
  1.1384 +  UnsetFlags(NODE_FORCE_XBL_BINDINGS | NODE_IS_IN_SHADOW_TREE);
  1.1385 +  
  1.1386 +#ifdef MOZ_XUL
  1.1387 +  nsXULElement* xulElem = nsXULElement::FromContent(this);
  1.1388 +  if (xulElem) {
  1.1389 +    xulElem->SetXULBindingParent(nullptr);
  1.1390 +  }
  1.1391 +  else
  1.1392 +#endif
  1.1393 +  {
  1.1394 +    nsDOMSlots *slots = GetExistingDOMSlots();
  1.1395 +    if (slots) {
  1.1396 +      slots->mBindingParent = nullptr;
  1.1397 +      slots->mContainingShadow = nullptr;
  1.1398 +    }
  1.1399 +  }
  1.1400 +
  1.1401 +  // This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree, 
  1.1402 +  //  because it has to happen after unsetting the parent pointer, but before
  1.1403 +  //  recursively unbinding the kids.
  1.1404 +  if (IsHTML()) {
  1.1405 +    ResetDir(this);
  1.1406 +  }
  1.1407 +
  1.1408 +  if (aDeep) {
  1.1409 +    // Do the kids. Don't call GetChildCount() here since that'll force
  1.1410 +    // XUL to generate template children, which there is no need for since
  1.1411 +    // all we're going to do is unbind them anyway.
  1.1412 +    uint32_t i, n = mAttrsAndChildren.ChildCount();
  1.1413 +
  1.1414 +    for (i = 0; i < n; ++i) {
  1.1415 +      // Note that we pass false for aNullParent here, since we don't want
  1.1416 +      // the kids to forget us.  We _do_ want them to forget their binding
  1.1417 +      // parent, though, since this only walks non-anonymous kids.
  1.1418 +      mAttrsAndChildren.ChildAt(i)->UnbindFromTree(true, false);
  1.1419 +    }
  1.1420 +  }
  1.1421 +
  1.1422 +  nsNodeUtils::ParentChainChanged(this);
  1.1423 +}
  1.1424 +
  1.1425 +nsICSSDeclaration*
  1.1426 +Element::GetSMILOverrideStyle()
  1.1427 +{
  1.1428 +  Element::nsDOMSlots *slots = DOMSlots();
  1.1429 +
  1.1430 +  if (!slots->mSMILOverrideStyle) {
  1.1431 +    slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true);
  1.1432 +  }
  1.1433 +
  1.1434 +  return slots->mSMILOverrideStyle;
  1.1435 +}
  1.1436 +
  1.1437 +css::StyleRule*
  1.1438 +Element::GetSMILOverrideStyleRule()
  1.1439 +{
  1.1440 +  Element::nsDOMSlots *slots = GetExistingDOMSlots();
  1.1441 +  return slots ? slots->mSMILOverrideStyleRule.get() : nullptr;
  1.1442 +}
  1.1443 +
  1.1444 +nsresult
  1.1445 +Element::SetSMILOverrideStyleRule(css::StyleRule* aStyleRule,
  1.1446 +                                           bool aNotify)
  1.1447 +{
  1.1448 +  Element::nsDOMSlots *slots = DOMSlots();
  1.1449 +
  1.1450 +  slots->mSMILOverrideStyleRule = aStyleRule;
  1.1451 +
  1.1452 +  if (aNotify) {
  1.1453 +    nsIDocument* doc = GetCurrentDoc();
  1.1454 +    // Only need to request a restyle if we're in a document.  (We might not
  1.1455 +    // be in a document, if we're clearing animation effects on a target node
  1.1456 +    // that's been detached since the previous animation sample.)
  1.1457 +    if (doc) {
  1.1458 +      nsCOMPtr<nsIPresShell> shell = doc->GetShell();
  1.1459 +      if (shell) {
  1.1460 +        shell->RestyleForAnimation(this, eRestyle_Self);
  1.1461 +      }
  1.1462 +    }
  1.1463 +  }
  1.1464 +
  1.1465 +  return NS_OK;
  1.1466 +}
  1.1467 +
  1.1468 +bool
  1.1469 +Element::IsLabelable() const
  1.1470 +{
  1.1471 +  return false;
  1.1472 +}
  1.1473 +
  1.1474 +css::StyleRule*
  1.1475 +Element::GetInlineStyleRule()
  1.1476 +{
  1.1477 +  return nullptr;
  1.1478 +}
  1.1479 +
  1.1480 +nsresult
  1.1481 +Element::SetInlineStyleRule(css::StyleRule* aStyleRule,
  1.1482 +                            const nsAString* aSerialized,
  1.1483 +                            bool aNotify)
  1.1484 +{
  1.1485 +  NS_NOTYETIMPLEMENTED("Element::SetInlineStyleRule");
  1.1486 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.1487 +}
  1.1488 +
  1.1489 +NS_IMETHODIMP_(bool)
  1.1490 +Element::IsAttributeMapped(const nsIAtom* aAttribute) const
  1.1491 +{
  1.1492 +  return false;
  1.1493 +}
  1.1494 +
  1.1495 +nsChangeHint
  1.1496 +Element::GetAttributeChangeHint(const nsIAtom* aAttribute,
  1.1497 +                                int32_t aModType) const
  1.1498 +{
  1.1499 +  return nsChangeHint(0);
  1.1500 +}
  1.1501 +
  1.1502 +nsIAtom *
  1.1503 +Element::GetClassAttributeName() const
  1.1504 +{
  1.1505 +  return nullptr;
  1.1506 +}
  1.1507 +
  1.1508 +bool
  1.1509 +Element::FindAttributeDependence(const nsIAtom* aAttribute,
  1.1510 +                                 const MappedAttributeEntry* const aMaps[],
  1.1511 +                                 uint32_t aMapCount)
  1.1512 +{
  1.1513 +  for (uint32_t mapindex = 0; mapindex < aMapCount; ++mapindex) {
  1.1514 +    for (const MappedAttributeEntry* map = aMaps[mapindex];
  1.1515 +         map->attribute; ++map) {
  1.1516 +      if (aAttribute == *map->attribute) {
  1.1517 +        return true;
  1.1518 +      }
  1.1519 +    }
  1.1520 +  }
  1.1521 +
  1.1522 +  return false;
  1.1523 +}
  1.1524 +
  1.1525 +already_AddRefed<nsINodeInfo>
  1.1526 +Element::GetExistingAttrNameFromQName(const nsAString& aStr) const
  1.1527 +{
  1.1528 +  const nsAttrName* name = InternalGetExistingAttrNameFromQName(aStr);
  1.1529 +  if (!name) {
  1.1530 +    return nullptr;
  1.1531 +  }
  1.1532 +
  1.1533 +  nsCOMPtr<nsINodeInfo> nodeInfo;
  1.1534 +  if (name->IsAtom()) {
  1.1535 +    nodeInfo = mNodeInfo->NodeInfoManager()->
  1.1536 +      GetNodeInfo(name->Atom(), nullptr, kNameSpaceID_None,
  1.1537 +                  nsIDOMNode::ATTRIBUTE_NODE);
  1.1538 +  }
  1.1539 +  else {
  1.1540 +    nodeInfo = name->NodeInfo();
  1.1541 +  }
  1.1542 +
  1.1543 +  return nodeInfo.forget();
  1.1544 +}
  1.1545 +
  1.1546 +// static
  1.1547 +bool
  1.1548 +Element::ShouldBlur(nsIContent *aContent)
  1.1549 +{
  1.1550 +  // Determine if the current element is focused, if it is not focused
  1.1551 +  // then we should not try to blur
  1.1552 +  nsIDocument *document = aContent->GetDocument();
  1.1553 +  if (!document)
  1.1554 +    return false;
  1.1555 +
  1.1556 +  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(document->GetWindow());
  1.1557 +  if (!window)
  1.1558 +    return false;
  1.1559 +
  1.1560 +  nsCOMPtr<nsPIDOMWindow> focusedFrame;
  1.1561 +  nsIContent* contentToBlur =
  1.1562 +    nsFocusManager::GetFocusedDescendant(window, false, getter_AddRefs(focusedFrame));
  1.1563 +  if (contentToBlur == aContent)
  1.1564 +    return true;
  1.1565 +
  1.1566 +  // if focus on this element would get redirected, then check the redirected
  1.1567 +  // content as well when blurring.
  1.1568 +  return (contentToBlur && nsFocusManager::GetRedirectedFocus(aContent) == contentToBlur);
  1.1569 +}
  1.1570 +
  1.1571 +bool
  1.1572 +Element::IsNodeOfType(uint32_t aFlags) const
  1.1573 +{
  1.1574 +  return !(aFlags & ~eCONTENT);
  1.1575 +}
  1.1576 +
  1.1577 +/* static */
  1.1578 +nsresult
  1.1579 +Element::DispatchEvent(nsPresContext* aPresContext,
  1.1580 +                       WidgetEvent* aEvent,
  1.1581 +                       nsIContent* aTarget,
  1.1582 +                       bool aFullDispatch,
  1.1583 +                       nsEventStatus* aStatus)
  1.1584 +{
  1.1585 +  NS_PRECONDITION(aTarget, "Must have target");
  1.1586 +  NS_PRECONDITION(aEvent, "Must have source event");
  1.1587 +  NS_PRECONDITION(aStatus, "Null out param?");
  1.1588 +
  1.1589 +  if (!aPresContext) {
  1.1590 +    return NS_OK;
  1.1591 +  }
  1.1592 +
  1.1593 +  nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
  1.1594 +  if (!shell) {
  1.1595 +    return NS_OK;
  1.1596 +  }
  1.1597 +
  1.1598 +  if (aFullDispatch) {
  1.1599 +    return shell->HandleEventWithTarget(aEvent, nullptr, aTarget, aStatus);
  1.1600 +  }
  1.1601 +
  1.1602 +  return shell->HandleDOMEventWithTarget(aTarget, aEvent, aStatus);
  1.1603 +}
  1.1604 +
  1.1605 +/* static */
  1.1606 +nsresult
  1.1607 +Element::DispatchClickEvent(nsPresContext* aPresContext,
  1.1608 +                            WidgetInputEvent* aSourceEvent,
  1.1609 +                            nsIContent* aTarget,
  1.1610 +                            bool aFullDispatch,
  1.1611 +                            const EventFlags* aExtraEventFlags,
  1.1612 +                            nsEventStatus* aStatus)
  1.1613 +{
  1.1614 +  NS_PRECONDITION(aTarget, "Must have target");
  1.1615 +  NS_PRECONDITION(aSourceEvent, "Must have source event");
  1.1616 +  NS_PRECONDITION(aStatus, "Null out param?");
  1.1617 +
  1.1618 +  WidgetMouseEvent event(aSourceEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK,
  1.1619 +                         aSourceEvent->widget, WidgetMouseEvent::eReal);
  1.1620 +  event.refPoint = aSourceEvent->refPoint;
  1.1621 +  uint32_t clickCount = 1;
  1.1622 +  float pressure = 0;
  1.1623 +  uint16_t inputSource = 0;
  1.1624 +  WidgetMouseEvent* sourceMouseEvent = aSourceEvent->AsMouseEvent();
  1.1625 +  if (sourceMouseEvent) {
  1.1626 +    clickCount = sourceMouseEvent->clickCount;
  1.1627 +    pressure = sourceMouseEvent->pressure;
  1.1628 +    inputSource = sourceMouseEvent->inputSource;
  1.1629 +  } else if (aSourceEvent->eventStructType == NS_KEY_EVENT) {
  1.1630 +    inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
  1.1631 +  }
  1.1632 +  event.pressure = pressure;
  1.1633 +  event.clickCount = clickCount;
  1.1634 +  event.inputSource = inputSource;
  1.1635 +  event.modifiers = aSourceEvent->modifiers;
  1.1636 +  if (aExtraEventFlags) {
  1.1637 +    // Be careful not to overwrite existing flags!
  1.1638 +    event.mFlags.Union(*aExtraEventFlags);
  1.1639 +  }
  1.1640 +
  1.1641 +  return DispatchEvent(aPresContext, &event, aTarget, aFullDispatch, aStatus);
  1.1642 +}
  1.1643 +
  1.1644 +nsIFrame*
  1.1645 +Element::GetPrimaryFrame(mozFlushType aType)
  1.1646 +{
  1.1647 +  nsIDocument* doc = GetCurrentDoc();
  1.1648 +  if (!doc) {
  1.1649 +    return nullptr;
  1.1650 +  }
  1.1651 +
  1.1652 +  // Cause a flush, so we get up-to-date frame
  1.1653 +  // information
  1.1654 +  if (aType != Flush_None) {
  1.1655 +    doc->FlushPendingNotifications(aType);
  1.1656 +  }
  1.1657 +
  1.1658 +  return GetPrimaryFrame();
  1.1659 +}
  1.1660 +
  1.1661 +//----------------------------------------------------------------------
  1.1662 +nsresult
  1.1663 +Element::LeaveLink(nsPresContext* aPresContext)
  1.1664 +{
  1.1665 +  nsILinkHandler *handler = aPresContext->GetLinkHandler();
  1.1666 +  if (!handler) {
  1.1667 +    return NS_OK;
  1.1668 +  }
  1.1669 +
  1.1670 +  return handler->OnLeaveLink();
  1.1671 +}
  1.1672 +
  1.1673 +nsresult
  1.1674 +Element::SetEventHandler(nsIAtom* aEventName,
  1.1675 +                         const nsAString& aValue,
  1.1676 +                         bool aDefer)
  1.1677 +{
  1.1678 +  nsIDocument *ownerDoc = OwnerDoc();
  1.1679 +  if (ownerDoc->IsLoadedAsData()) {
  1.1680 +    // Make this a no-op rather than throwing an error to avoid
  1.1681 +    // the error causing problems setting the attribute.
  1.1682 +    return NS_OK;
  1.1683 +  }
  1.1684 +
  1.1685 +  NS_PRECONDITION(aEventName, "Must have event name!");
  1.1686 +  bool defer = true;
  1.1687 +  EventListenerManager* manager =
  1.1688 +    GetEventListenerManagerForAttr(aEventName, &defer);
  1.1689 +  if (!manager) {
  1.1690 +    return NS_OK;
  1.1691 +  }
  1.1692 +
  1.1693 +  defer = defer && aDefer; // only defer if everyone agrees...
  1.1694 +  manager->SetEventHandler(aEventName, aValue,
  1.1695 +                           nsIProgrammingLanguage::JAVASCRIPT,
  1.1696 +                           defer, !nsContentUtils::IsChromeDoc(ownerDoc),
  1.1697 +                           this);
  1.1698 +  return NS_OK;
  1.1699 +}
  1.1700 +
  1.1701 +
  1.1702 +//----------------------------------------------------------------------
  1.1703 +
  1.1704 +const nsAttrName*
  1.1705 +Element::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
  1.1706 +{
  1.1707 +  return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
  1.1708 +}
  1.1709 +
  1.1710 +bool
  1.1711 +Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
  1.1712 +                               nsIAtom* aName,
  1.1713 +                               nsIAtom* aPrefix,
  1.1714 +                               const nsAttrValueOrString& aValue,
  1.1715 +                               bool aNotify,
  1.1716 +                               nsAttrValue& aOldValue,
  1.1717 +                               uint8_t* aModType,
  1.1718 +                               bool* aHasListeners)
  1.1719 +{
  1.1720 +  bool modification = false;
  1.1721 +  *aHasListeners = aNotify &&
  1.1722 +    nsContentUtils::HasMutationListeners(this,
  1.1723 +                                         NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
  1.1724 +                                         this);
  1.1725 +
  1.1726 +  // If we have no listeners and aNotify is false, we are almost certainly
  1.1727 +  // coming from the content sink and will almost certainly have no previous
  1.1728 +  // value.  Even if we do, setting the value is cheap when we have no
  1.1729 +  // listeners and don't plan to notify.  The check for aNotify here is an
  1.1730 +  // optimization, the check for *aHasListeners is a correctness issue.
  1.1731 +  if (*aHasListeners || aNotify) {
  1.1732 +    nsAttrInfo info(GetAttrInfo(aNamespaceID, aName));
  1.1733 +    if (info.mValue) {
  1.1734 +      // Check whether the old value is the same as the new one.  Note that we
  1.1735 +      // only need to actually _get_ the old value if we have listeners or
  1.1736 +      // if the element is a custom element (because it may have an
  1.1737 +      // attribute changed callback).
  1.1738 +      if (*aHasListeners || GetCustomElementData()) {
  1.1739 +        // Need to store the old value.
  1.1740 +        //
  1.1741 +        // If the current attribute value contains a pointer to some other data
  1.1742 +        // structure that gets updated in the process of setting the attribute
  1.1743 +        // we'll no longer have the old value of the attribute. Therefore, we
  1.1744 +        // should serialize the attribute value now to keep a snapshot.
  1.1745 +        //
  1.1746 +        // We have to serialize the value anyway in order to create the
  1.1747 +        // mutation event so there's no cost in doing it now.
  1.1748 +        aOldValue.SetToSerialized(*info.mValue);
  1.1749 +      }
  1.1750 +      bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
  1.1751 +      if (valueMatches && aPrefix == info.mName->GetPrefix()) {
  1.1752 +        return true;
  1.1753 +      }
  1.1754 +      modification = true;
  1.1755 +    }
  1.1756 +  }
  1.1757 +  *aModType = modification ?
  1.1758 +    static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) :
  1.1759 +    static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
  1.1760 +  return false;
  1.1761 +}
  1.1762 +
  1.1763 +bool
  1.1764 +Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
  1.1765 +                                nsIAtom* aPrefix,
  1.1766 +                                const nsAttrValueOrString& aValue,
  1.1767 +                                bool aNotify, nsAttrValue& aOldValue,
  1.1768 +                                uint8_t* aModType, bool* aHasListeners)
  1.1769 +{
  1.1770 +  if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
  1.1771 +                             aOldValue, aModType, aHasListeners)) {
  1.1772 +    return false;
  1.1773 +  }
  1.1774 +
  1.1775 +  nsAutoScriptBlocker scriptBlocker;
  1.1776 +  nsNodeUtils::AttributeSetToCurrentValue(this, aNamespaceID, aName);
  1.1777 +  return true;
  1.1778 +}
  1.1779 +
  1.1780 +nsresult
  1.1781 +Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
  1.1782 +                 nsIAtom* aPrefix, const nsAString& aValue,
  1.1783 +                 bool aNotify)
  1.1784 +{
  1.1785 +  // Keep this in sync with SetParsedAttr below
  1.1786 +
  1.1787 +  NS_ENSURE_ARG_POINTER(aName);
  1.1788 +  NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
  1.1789 +               "Don't call SetAttr with unknown namespace");
  1.1790 +
  1.1791 +  if (!mAttrsAndChildren.CanFitMoreAttrs()) {
  1.1792 +    return NS_ERROR_FAILURE;
  1.1793 +  }
  1.1794 +
  1.1795 +  uint8_t modType;
  1.1796 +  bool hasListeners;
  1.1797 +  nsAttrValueOrString value(aValue);
  1.1798 +  nsAttrValue oldValue;
  1.1799 +
  1.1800 +  if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
  1.1801 +                             oldValue, &modType, &hasListeners)) {
  1.1802 +    return NS_OK;
  1.1803 +  }
  1.1804 +
  1.1805 +  nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
  1.1806 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1807 +
  1.1808 +  if (aNotify) {
  1.1809 +    nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
  1.1810 +  }
  1.1811 +
  1.1812 +  // Hold a script blocker while calling ParseAttribute since that can call
  1.1813 +  // out to id-observers
  1.1814 +  nsAutoScriptBlocker scriptBlocker;
  1.1815 +
  1.1816 +  nsAttrValue attrValue;
  1.1817 +  if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
  1.1818 +    attrValue.SetTo(aValue);
  1.1819 +  }
  1.1820 +
  1.1821 +  return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
  1.1822 +                          attrValue, modType, hasListeners, aNotify,
  1.1823 +                          kCallAfterSetAttr);
  1.1824 +}
  1.1825 +
  1.1826 +nsresult
  1.1827 +Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
  1.1828 +                       nsIAtom* aPrefix, nsAttrValue& aParsedValue,
  1.1829 +                       bool aNotify)
  1.1830 +{
  1.1831 +  // Keep this in sync with SetAttr above
  1.1832 +
  1.1833 +  NS_ENSURE_ARG_POINTER(aName);
  1.1834 +  NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
  1.1835 +               "Don't call SetAttr with unknown namespace");
  1.1836 +
  1.1837 +  if (!mAttrsAndChildren.CanFitMoreAttrs()) {
  1.1838 +    return NS_ERROR_FAILURE;
  1.1839 +  }
  1.1840 +
  1.1841 +
  1.1842 +  uint8_t modType;
  1.1843 +  bool hasListeners;
  1.1844 +  nsAttrValueOrString value(aParsedValue);
  1.1845 +  nsAttrValue oldValue;
  1.1846 +
  1.1847 +  if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
  1.1848 +                             oldValue, &modType, &hasListeners)) {
  1.1849 +    return NS_OK;
  1.1850 +  }
  1.1851 +
  1.1852 +  nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
  1.1853 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1854 +
  1.1855 +  if (aNotify) {
  1.1856 +    nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
  1.1857 +  }
  1.1858 +
  1.1859 +  return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
  1.1860 +                          aParsedValue, modType, hasListeners, aNotify,
  1.1861 +                          kCallAfterSetAttr);
  1.1862 +}
  1.1863 +
  1.1864 +nsresult
  1.1865 +Element::SetAttrAndNotify(int32_t aNamespaceID,
  1.1866 +                          nsIAtom* aName,
  1.1867 +                          nsIAtom* aPrefix,
  1.1868 +                          const nsAttrValue& aOldValue,
  1.1869 +                          nsAttrValue& aParsedValue,
  1.1870 +                          uint8_t aModType,
  1.1871 +                          bool aFireMutation,
  1.1872 +                          bool aNotify,
  1.1873 +                          bool aCallAfterSetAttr)
  1.1874 +{
  1.1875 +  nsresult rv;
  1.1876 +
  1.1877 +  nsIDocument* document = GetCurrentDoc();
  1.1878 +  mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
  1.1879 +
  1.1880 +  nsMutationGuard::DidMutate();
  1.1881 +
  1.1882 +  // Copy aParsedValue for later use since it will be lost when we call
  1.1883 +  // SetAndTakeMappedAttr below
  1.1884 +  nsAttrValue aValueForAfterSetAttr;
  1.1885 +  if (aCallAfterSetAttr) {
  1.1886 +    aValueForAfterSetAttr.SetTo(aParsedValue);
  1.1887 +  }
  1.1888 +
  1.1889 +  bool hadValidDir = false;
  1.1890 +  bool hadDirAuto = false;
  1.1891 +
  1.1892 +  if (aNamespaceID == kNameSpaceID_None) {
  1.1893 +    if (aName == nsGkAtoms::dir) {
  1.1894 +      hadValidDir = HasValidDir() || IsHTML(nsGkAtoms::bdi);
  1.1895 +      hadDirAuto = HasDirAuto(); // already takes bdi into account
  1.1896 +    }
  1.1897 +
  1.1898 +    // XXXbz Perhaps we should push up the attribute mapping function
  1.1899 +    // stuff to Element?
  1.1900 +    if (!IsAttributeMapped(aName) ||
  1.1901 +        !SetMappedAttribute(document, aName, aParsedValue, &rv)) {
  1.1902 +      rv = mAttrsAndChildren.SetAndTakeAttr(aName, aParsedValue);
  1.1903 +    }
  1.1904 +  }
  1.1905 +  else {
  1.1906 +    nsCOMPtr<nsINodeInfo> ni;
  1.1907 +    ni = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix,
  1.1908 +                                                   aNamespaceID,
  1.1909 +                                                   nsIDOMNode::ATTRIBUTE_NODE);
  1.1910 +
  1.1911 +    rv = mAttrsAndChildren.SetAndTakeAttr(ni, aParsedValue);
  1.1912 +  }
  1.1913 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1914 +
  1.1915 +  if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
  1.1916 +    nsRefPtr<nsXBLBinding> binding = GetXBLBinding();
  1.1917 +    if (binding) {
  1.1918 +      binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
  1.1919 +    }
  1.1920 +  }
  1.1921 +
  1.1922 +  UpdateState(aNotify);
  1.1923 +
  1.1924 +  nsIDocument* ownerDoc = OwnerDoc();
  1.1925 +  if (ownerDoc && GetCustomElementData()) {
  1.1926 +    nsCOMPtr<nsIAtom> oldValueAtom = aOldValue.GetAsAtom();
  1.1927 +    nsCOMPtr<nsIAtom> newValueAtom = aValueForAfterSetAttr.GetAsAtom();
  1.1928 +    LifecycleCallbackArgs args = {
  1.1929 +      nsDependentAtomString(aName),
  1.1930 +      aModType == nsIDOMMutationEvent::ADDITION ?
  1.1931 +        NullString() : nsDependentAtomString(oldValueAtom),
  1.1932 +      nsDependentAtomString(newValueAtom)
  1.1933 +    };
  1.1934 +
  1.1935 +    ownerDoc->EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, this, &args);
  1.1936 +  }
  1.1937 +
  1.1938 +  if (aCallAfterSetAttr) {
  1.1939 +    rv = AfterSetAttr(aNamespaceID, aName, &aValueForAfterSetAttr, aNotify);
  1.1940 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1941 +
  1.1942 +    if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
  1.1943 +      OnSetDirAttr(this, &aValueForAfterSetAttr,
  1.1944 +                   hadValidDir, hadDirAuto, aNotify);
  1.1945 +    }
  1.1946 +  }
  1.1947 +
  1.1948 +  if (aNotify) {
  1.1949 +    nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
  1.1950 +  }
  1.1951 +
  1.1952 +  if (aFireMutation) {
  1.1953 +    InternalMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
  1.1954 +
  1.1955 +    nsAutoString ns;
  1.1956 +    nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
  1.1957 +    Attr* attrNode =
  1.1958 +      GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName));
  1.1959 +    mutation.mRelatedNode = attrNode;
  1.1960 +
  1.1961 +    mutation.mAttrName = aName;
  1.1962 +    nsAutoString newValue;
  1.1963 +    GetAttr(aNamespaceID, aName, newValue);
  1.1964 +    if (!newValue.IsEmpty()) {
  1.1965 +      mutation.mNewAttrValue = do_GetAtom(newValue);
  1.1966 +    }
  1.1967 +    if (!aOldValue.IsEmptyString()) {
  1.1968 +      mutation.mPrevAttrValue = aOldValue.GetAsAtom();
  1.1969 +    }
  1.1970 +    mutation.mAttrChange = aModType;
  1.1971 +
  1.1972 +    mozAutoSubtreeModified subtree(OwnerDoc(), this);
  1.1973 +    (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
  1.1974 +  }
  1.1975 +
  1.1976 +  return NS_OK;
  1.1977 +}
  1.1978 +
  1.1979 +bool
  1.1980 +Element::ParseAttribute(int32_t aNamespaceID,
  1.1981 +                        nsIAtom* aAttribute,
  1.1982 +                        const nsAString& aValue,
  1.1983 +                        nsAttrValue& aResult)
  1.1984 +{
  1.1985 +  return false;
  1.1986 +}
  1.1987 +
  1.1988 +bool
  1.1989 +Element::SetMappedAttribute(nsIDocument* aDocument,
  1.1990 +                            nsIAtom* aName,
  1.1991 +                            nsAttrValue& aValue,
  1.1992 +                            nsresult* aRetval)
  1.1993 +{
  1.1994 +  *aRetval = NS_OK;
  1.1995 +  return false;
  1.1996 +}
  1.1997 +
  1.1998 +EventListenerManager*
  1.1999 +Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
  1.2000 +                                        bool* aDefer)
  1.2001 +{
  1.2002 +  *aDefer = true;
  1.2003 +  return GetOrCreateListenerManager();
  1.2004 +}
  1.2005 +
  1.2006 +Element::nsAttrInfo
  1.2007 +Element::GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const
  1.2008 +{
  1.2009 +  NS_ASSERTION(nullptr != aName, "must have attribute name");
  1.2010 +  NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
  1.2011 +               "must have a real namespace ID!");
  1.2012 +
  1.2013 +  int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNamespaceID);
  1.2014 +  if (index >= 0) {
  1.2015 +    return nsAttrInfo(mAttrsAndChildren.AttrNameAt(index),
  1.2016 +                      mAttrsAndChildren.AttrAt(index));
  1.2017 +  }
  1.2018 +
  1.2019 +  return nsAttrInfo(nullptr, nullptr);
  1.2020 +}
  1.2021 +  
  1.2022 +
  1.2023 +bool
  1.2024 +Element::GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
  1.2025 +                 nsAString& aResult) const
  1.2026 +{
  1.2027 +  DOMString str;
  1.2028 +  bool haveAttr = GetAttr(aNameSpaceID, aName, str);
  1.2029 +  str.ToString(aResult);
  1.2030 +  return haveAttr;
  1.2031 +}
  1.2032 +
  1.2033 +int32_t
  1.2034 +Element::FindAttrValueIn(int32_t aNameSpaceID,
  1.2035 +                         nsIAtom* aName,
  1.2036 +                         AttrValuesArray* aValues,
  1.2037 +                         nsCaseTreatment aCaseSensitive) const
  1.2038 +{
  1.2039 +  NS_ASSERTION(aName, "Must have attr name");
  1.2040 +  NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
  1.2041 +  NS_ASSERTION(aValues, "Null value array");
  1.2042 +  
  1.2043 +  const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
  1.2044 +  if (val) {
  1.2045 +    for (int32_t i = 0; aValues[i]; ++i) {
  1.2046 +      if (val->Equals(*aValues[i], aCaseSensitive)) {
  1.2047 +        return i;
  1.2048 +      }
  1.2049 +    }
  1.2050 +    return ATTR_VALUE_NO_MATCH;
  1.2051 +  }
  1.2052 +  return ATTR_MISSING;
  1.2053 +}
  1.2054 +
  1.2055 +nsresult
  1.2056 +Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
  1.2057 +                   bool aNotify)
  1.2058 +{
  1.2059 +  NS_ASSERTION(nullptr != aName, "must have attribute name");
  1.2060 +
  1.2061 +  int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
  1.2062 +  if (index < 0) {
  1.2063 +    return NS_OK;
  1.2064 +  }
  1.2065 +
  1.2066 +  nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
  1.2067 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2068 +
  1.2069 +  nsIDocument *document = GetCurrentDoc();
  1.2070 +  mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
  1.2071 +
  1.2072 +  if (aNotify) {
  1.2073 +    nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
  1.2074 +                                     nsIDOMMutationEvent::REMOVAL);
  1.2075 +  }
  1.2076 +
  1.2077 +  bool hasMutationListeners = aNotify &&
  1.2078 +    nsContentUtils::HasMutationListeners(this,
  1.2079 +                                         NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
  1.2080 +                                         this);
  1.2081 +
  1.2082 +  // Grab the attr node if needed before we remove it from the attr map
  1.2083 +  nsRefPtr<Attr> attrNode;
  1.2084 +  if (hasMutationListeners) {
  1.2085 +    nsAutoString ns;
  1.2086 +    nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
  1.2087 +    attrNode = GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName));
  1.2088 +  }
  1.2089 +
  1.2090 +  // Clear binding to nsIDOMMozNamedAttrMap
  1.2091 +  nsDOMSlots *slots = GetExistingDOMSlots();
  1.2092 +  if (slots && slots->mAttributeMap) {
  1.2093 +    slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
  1.2094 +  }
  1.2095 +
  1.2096 +  // The id-handling code, and in the future possibly other code, need to
  1.2097 +  // react to unexpected attribute changes.
  1.2098 +  nsMutationGuard::DidMutate();
  1.2099 +
  1.2100 +  bool hadValidDir = false;
  1.2101 +  bool hadDirAuto = false;
  1.2102 +
  1.2103 +  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
  1.2104 +    hadValidDir = HasValidDir() || IsHTML(nsGkAtoms::bdi);
  1.2105 +    hadDirAuto = HasDirAuto(); // already takes bdi into account
  1.2106 +  }
  1.2107 +
  1.2108 +  nsAttrValue oldValue;
  1.2109 +  rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
  1.2110 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2111 +
  1.2112 +  if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
  1.2113 +    nsRefPtr<nsXBLBinding> binding = GetXBLBinding();
  1.2114 +    if (binding) {
  1.2115 +      binding->AttributeChanged(aName, aNameSpaceID, true, aNotify);
  1.2116 +    }
  1.2117 +  }
  1.2118 +
  1.2119 +  UpdateState(aNotify);
  1.2120 +
  1.2121 +  nsIDocument* ownerDoc = OwnerDoc();
  1.2122 +  if (ownerDoc && GetCustomElementData()) {
  1.2123 +    nsCOMPtr<nsIAtom> oldValueAtom = oldValue.GetAsAtom();
  1.2124 +    LifecycleCallbackArgs args = {
  1.2125 +      nsDependentAtomString(aName),
  1.2126 +      nsDependentAtomString(oldValueAtom),
  1.2127 +      NullString()
  1.2128 +    };
  1.2129 +
  1.2130 +    ownerDoc->EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, this, &args);
  1.2131 +  }
  1.2132 +
  1.2133 +  if (aNotify) {
  1.2134 +    nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
  1.2135 +                                  nsIDOMMutationEvent::REMOVAL);
  1.2136 +  }
  1.2137 +
  1.2138 +  rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify);
  1.2139 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2140 +
  1.2141 +  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
  1.2142 +    OnSetDirAttr(this, nullptr, hadValidDir, hadDirAuto, aNotify);
  1.2143 +  }
  1.2144 +
  1.2145 +  if (hasMutationListeners) {
  1.2146 +    InternalMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
  1.2147 +
  1.2148 +    mutation.mRelatedNode = attrNode;
  1.2149 +    mutation.mAttrName = aName;
  1.2150 +
  1.2151 +    nsAutoString value;
  1.2152 +    oldValue.ToString(value);
  1.2153 +    if (!value.IsEmpty())
  1.2154 +      mutation.mPrevAttrValue = do_GetAtom(value);
  1.2155 +    mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
  1.2156 +
  1.2157 +    mozAutoSubtreeModified subtree(OwnerDoc(), this);
  1.2158 +    (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
  1.2159 +  }
  1.2160 +
  1.2161 +  return NS_OK;
  1.2162 +}
  1.2163 +
  1.2164 +const nsAttrName*
  1.2165 +Element::GetAttrNameAt(uint32_t aIndex) const
  1.2166 +{
  1.2167 +  return mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
  1.2168 +}
  1.2169 +
  1.2170 +uint32_t
  1.2171 +Element::GetAttrCount() const
  1.2172 +{
  1.2173 +  return mAttrsAndChildren.AttrCount();
  1.2174 +}
  1.2175 +
  1.2176 +void
  1.2177 +Element::DescribeAttribute(uint32_t index, nsAString& aOutDescription) const
  1.2178 +{
  1.2179 +  // name
  1.2180 +  mAttrsAndChildren.AttrNameAt(index)->GetQualifiedName(aOutDescription);
  1.2181 +
  1.2182 +  // value
  1.2183 +  aOutDescription.AppendLiteral("=\"");
  1.2184 +  nsAutoString value;
  1.2185 +  mAttrsAndChildren.AttrAt(index)->ToString(value);
  1.2186 +  for (int i = value.Length(); i >= 0; --i) {
  1.2187 +    if (value[i] == char16_t('"'))
  1.2188 +      value.Insert(char16_t('\\'), uint32_t(i));
  1.2189 +  }
  1.2190 +  aOutDescription.Append(value);
  1.2191 +  aOutDescription.AppendLiteral("\"");
  1.2192 +}
  1.2193 +
  1.2194 +#ifdef DEBUG
  1.2195 +void
  1.2196 +Element::ListAttributes(FILE* out) const
  1.2197 +{
  1.2198 +  uint32_t index, count = mAttrsAndChildren.AttrCount();
  1.2199 +  for (index = 0; index < count; index++) {
  1.2200 +    nsAutoString attributeDescription;
  1.2201 +    DescribeAttribute(index, attributeDescription);
  1.2202 +
  1.2203 +    fputs(" ", out);
  1.2204 +    fputs(NS_LossyConvertUTF16toASCII(attributeDescription).get(), out);
  1.2205 +  }
  1.2206 +}
  1.2207 +
  1.2208 +void
  1.2209 +Element::List(FILE* out, int32_t aIndent,
  1.2210 +              const nsCString& aPrefix) const
  1.2211 +{
  1.2212 +  int32_t indent;
  1.2213 +  for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  1.2214 +
  1.2215 +  fputs(aPrefix.get(), out);
  1.2216 +
  1.2217 +  fputs(NS_LossyConvertUTF16toASCII(mNodeInfo->QualifiedName()).get(), out);
  1.2218 +
  1.2219 +  fprintf(out, "@%p", (void *)this);
  1.2220 +
  1.2221 +  ListAttributes(out);
  1.2222 +
  1.2223 +  fprintf(out, " state=[%llx]",
  1.2224 +          static_cast<unsigned long long>(State().GetInternalValue()));
  1.2225 +  fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
  1.2226 +  if (IsCommonAncestorForRangeInSelection()) {
  1.2227 +    nsRange::RangeHashTable* ranges =
  1.2228 +      static_cast<nsRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
  1.2229 +    fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
  1.2230 +  }
  1.2231 +  fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
  1.2232 +  fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get());
  1.2233 +
  1.2234 +  nsIContent* child = GetFirstChild();
  1.2235 +  if (child) {
  1.2236 +    fputs("\n", out);
  1.2237 +    
  1.2238 +    for (; child; child = child->GetNextSibling()) {
  1.2239 +      child->List(out, aIndent + 1);
  1.2240 +    }
  1.2241 +
  1.2242 +    for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  1.2243 +  }
  1.2244 +
  1.2245 +  fputs(">\n", out);
  1.2246 +  
  1.2247 +  Element* nonConstThis = const_cast<Element*>(this);
  1.2248 +
  1.2249 +  // XXX sXBL/XBL2 issue! Owner or current document?
  1.2250 +  nsIDocument *document = OwnerDoc();
  1.2251 +
  1.2252 +  // Note: not listing nsIAnonymousContentCreator-created content...
  1.2253 +
  1.2254 +  nsBindingManager* bindingManager = document->BindingManager();
  1.2255 +  nsCOMPtr<nsIDOMNodeList> anonymousChildren;
  1.2256 +  bindingManager->GetAnonymousNodesFor(nonConstThis,
  1.2257 +                                       getter_AddRefs(anonymousChildren));
  1.2258 +
  1.2259 +  if (anonymousChildren) {
  1.2260 +    uint32_t length = 0;
  1.2261 +    anonymousChildren->GetLength(&length);
  1.2262 +
  1.2263 +    for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  1.2264 +    fputs("anonymous-children<\n", out);
  1.2265 +
  1.2266 +    for (uint32_t i = 0; i < length; ++i) {
  1.2267 +      nsCOMPtr<nsIDOMNode> node;
  1.2268 +      anonymousChildren->Item(i, getter_AddRefs(node));
  1.2269 +      nsCOMPtr<nsIContent> child = do_QueryInterface(node);
  1.2270 +      child->List(out, aIndent + 1);
  1.2271 +    }
  1.2272 +
  1.2273 +    for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  1.2274 +    fputs(">\n", out);
  1.2275 +
  1.2276 +    bool outHeader = false;
  1.2277 +    ExplicitChildIterator iter(nonConstThis);
  1.2278 +    for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
  1.2279 +      if (!outHeader) {
  1.2280 +        outHeader = true;
  1.2281 +
  1.2282 +        for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  1.2283 +        fputs("content-list<\n", out);
  1.2284 +      }
  1.2285 +
  1.2286 +      child->List(out, aIndent + 1);
  1.2287 +    }
  1.2288 +
  1.2289 +    if (outHeader) {
  1.2290 +      for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  1.2291 +      fputs(">\n", out);
  1.2292 +    }
  1.2293 +  }
  1.2294 +}
  1.2295 +
  1.2296 +void
  1.2297 +Element::DumpContent(FILE* out, int32_t aIndent,
  1.2298 +                     bool aDumpAll) const
  1.2299 +{
  1.2300 +  int32_t indent;
  1.2301 +  for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  1.2302 +
  1.2303 +  const nsString& buf = mNodeInfo->QualifiedName();
  1.2304 +  fputs("<", out);
  1.2305 +  fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
  1.2306 +
  1.2307 +  if(aDumpAll) ListAttributes(out);
  1.2308 +
  1.2309 +  fputs(">", out);
  1.2310 +
  1.2311 +  if(aIndent) fputs("\n", out);
  1.2312 +
  1.2313 +  for (nsIContent* child = GetFirstChild();
  1.2314 +       child;
  1.2315 +       child = child->GetNextSibling()) {
  1.2316 +    int32_t indent = aIndent ? aIndent + 1 : 0;
  1.2317 +    child->DumpContent(out, indent, aDumpAll);
  1.2318 +  }
  1.2319 +  for (indent = aIndent; --indent >= 0; ) fputs("  ", out);
  1.2320 +  fputs("</", out);
  1.2321 +  fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
  1.2322 +  fputs(">", out);
  1.2323 +
  1.2324 +  if(aIndent) fputs("\n", out);
  1.2325 +}
  1.2326 +#endif
  1.2327 +
  1.2328 +void
  1.2329 +Element::Describe(nsAString& aOutDescription) const
  1.2330 +{
  1.2331 +  aOutDescription.Append(mNodeInfo->QualifiedName());
  1.2332 +  aOutDescription.AppendPrintf("@%p", (void *)this);
  1.2333 +
  1.2334 +  uint32_t index, count = mAttrsAndChildren.AttrCount();
  1.2335 +  for (index = 0; index < count; index++) {
  1.2336 +    aOutDescription.Append(' ');
  1.2337 +    nsAutoString attributeDescription;
  1.2338 +    DescribeAttribute(index, attributeDescription);
  1.2339 +    aOutDescription.Append(attributeDescription);
  1.2340 +  }
  1.2341 +}
  1.2342 +
  1.2343 +bool
  1.2344 +Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
  1.2345 +                                              nsIURI** aURI) const
  1.2346 +{
  1.2347 +  if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
  1.2348 +      (!aVisitor.mEvent->mFlags.mIsTrusted &&
  1.2349 +       (aVisitor.mEvent->message != NS_MOUSE_CLICK) &&
  1.2350 +       (aVisitor.mEvent->message != NS_KEY_PRESS) &&
  1.2351 +       (aVisitor.mEvent->message != NS_UI_ACTIVATE)) ||
  1.2352 +      !aVisitor.mPresContext ||
  1.2353 +      aVisitor.mEvent->mFlags.mMultipleActionsPrevented) {
  1.2354 +    return false;
  1.2355 +  }
  1.2356 +
  1.2357 +  // Make sure we actually are a link
  1.2358 +  return IsLink(aURI);
  1.2359 +}
  1.2360 +
  1.2361 +nsresult
  1.2362 +Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
  1.2363 +{
  1.2364 +  // Optimisation: return early if this event doesn't interest us.
  1.2365 +  // IMPORTANT: this switch and the switch below it must be kept in sync!
  1.2366 +  switch (aVisitor.mEvent->message) {
  1.2367 +  case NS_MOUSE_ENTER_SYNTH:
  1.2368 +  case NS_FOCUS_CONTENT:
  1.2369 +  case NS_MOUSE_EXIT_SYNTH:
  1.2370 +  case NS_BLUR_CONTENT:
  1.2371 +    break;
  1.2372 +  default:
  1.2373 +    return NS_OK;
  1.2374 +  }
  1.2375 +
  1.2376 +  // Make sure we meet the preconditions before continuing
  1.2377 +  nsCOMPtr<nsIURI> absURI;
  1.2378 +  if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
  1.2379 +    return NS_OK;
  1.2380 +  }
  1.2381 +
  1.2382 +  nsresult rv = NS_OK;
  1.2383 +
  1.2384 +  // We do the status bar updates in PreHandleEvent so that the status bar gets
  1.2385 +  // updated even if the event is consumed before we have a chance to set it.
  1.2386 +  switch (aVisitor.mEvent->message) {
  1.2387 +  // Set the status bar similarly for mouseover and focus
  1.2388 +  case NS_MOUSE_ENTER_SYNTH:
  1.2389 +    aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  1.2390 +    // FALL THROUGH
  1.2391 +  case NS_FOCUS_CONTENT: {
  1.2392 +    InternalFocusEvent* focusEvent = aVisitor.mEvent->AsFocusEvent();
  1.2393 +    if (!focusEvent || !focusEvent->isRefocus) {
  1.2394 +      nsAutoString target;
  1.2395 +      GetLinkTarget(target);
  1.2396 +      nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
  1.2397 +                                  false, true, true);
  1.2398 +      // Make sure any ancestor links don't also TriggerLink
  1.2399 +      aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
  1.2400 +    }
  1.2401 +    break;
  1.2402 +  }
  1.2403 +  case NS_MOUSE_EXIT_SYNTH:
  1.2404 +    aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  1.2405 +    // FALL THROUGH
  1.2406 +  case NS_BLUR_CONTENT:
  1.2407 +    rv = LeaveLink(aVisitor.mPresContext);
  1.2408 +    if (NS_SUCCEEDED(rv)) {
  1.2409 +      aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
  1.2410 +    }
  1.2411 +    break;
  1.2412 +
  1.2413 +  default:
  1.2414 +    // switch not in sync with the optimization switch earlier in this function
  1.2415 +    NS_NOTREACHED("switch statements not in sync");
  1.2416 +    return NS_ERROR_UNEXPECTED;
  1.2417 +  }
  1.2418 +
  1.2419 +  return rv;
  1.2420 +}
  1.2421 +
  1.2422 +nsresult
  1.2423 +Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor)
  1.2424 +{
  1.2425 +  // Optimisation: return early if this event doesn't interest us.
  1.2426 +  // IMPORTANT: this switch and the switch below it must be kept in sync!
  1.2427 +  switch (aVisitor.mEvent->message) {
  1.2428 +  case NS_MOUSE_BUTTON_DOWN:
  1.2429 +  case NS_MOUSE_CLICK:
  1.2430 +  case NS_UI_ACTIVATE:
  1.2431 +  case NS_KEY_PRESS:
  1.2432 +    break;
  1.2433 +  default:
  1.2434 +    return NS_OK;
  1.2435 +  }
  1.2436 +
  1.2437 +  // Make sure we meet the preconditions before continuing
  1.2438 +  nsCOMPtr<nsIURI> absURI;
  1.2439 +  if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
  1.2440 +    return NS_OK;
  1.2441 +  }
  1.2442 +
  1.2443 +  nsresult rv = NS_OK;
  1.2444 +
  1.2445 +  switch (aVisitor.mEvent->message) {
  1.2446 +  case NS_MOUSE_BUTTON_DOWN:
  1.2447 +    {
  1.2448 +      if (aVisitor.mEvent->AsMouseEvent()->button ==
  1.2449 +            WidgetMouseEvent::eLeftButton) {
  1.2450 +        // don't make the link grab the focus if there is no link handler
  1.2451 +        nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler();
  1.2452 +        nsIDocument *document = GetCurrentDoc();
  1.2453 +        if (handler && document) {
  1.2454 +          nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.2455 +          if (fm) {
  1.2456 +            aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
  1.2457 +            nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
  1.2458 +            fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE |
  1.2459 +                               nsIFocusManager::FLAG_NOSCROLL);
  1.2460 +          }
  1.2461 +
  1.2462 +          EventStateManager::SetActiveManager(
  1.2463 +            aVisitor.mPresContext->EventStateManager(), this);
  1.2464 +        }
  1.2465 +      }
  1.2466 +    }
  1.2467 +    break;
  1.2468 +
  1.2469 +  case NS_MOUSE_CLICK: {
  1.2470 +    WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
  1.2471 +    if (mouseEvent->IsLeftClickEvent()) {
  1.2472 +      if (mouseEvent->IsControl() || mouseEvent->IsMeta() ||
  1.2473 +          mouseEvent->IsAlt() ||mouseEvent->IsShift()) {
  1.2474 +        break;
  1.2475 +      }
  1.2476 +
  1.2477 +      // The default action is simply to dispatch DOMActivate
  1.2478 +      nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
  1.2479 +      if (shell) {
  1.2480 +        // single-click
  1.2481 +        nsEventStatus status = nsEventStatus_eIgnore;
  1.2482 +        InternalUIEvent actEvent(mouseEvent->mFlags.mIsTrusted, NS_UI_ACTIVATE);
  1.2483 +        actEvent.detail = 1;
  1.2484 +
  1.2485 +        rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
  1.2486 +        if (NS_SUCCEEDED(rv)) {
  1.2487 +          aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  1.2488 +        }
  1.2489 +      }
  1.2490 +    }
  1.2491 +    break;
  1.2492 +  }
  1.2493 +  case NS_UI_ACTIVATE:
  1.2494 +    {
  1.2495 +      if (aVisitor.mEvent->originalTarget == this) {
  1.2496 +        nsAutoString target;
  1.2497 +        GetLinkTarget(target);
  1.2498 +        nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
  1.2499 +                                    true, true,
  1.2500 +                                    aVisitor.mEvent->mFlags.mIsTrusted);
  1.2501 +        aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  1.2502 +      }
  1.2503 +    }
  1.2504 +    break;
  1.2505 +
  1.2506 +  case NS_KEY_PRESS:
  1.2507 +    {
  1.2508 +      WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
  1.2509 +      if (keyEvent && keyEvent->keyCode == NS_VK_RETURN) {
  1.2510 +        nsEventStatus status = nsEventStatus_eIgnore;
  1.2511 +        rv = DispatchClickEvent(aVisitor.mPresContext, keyEvent, this,
  1.2512 +                                false, nullptr, &status);
  1.2513 +        if (NS_SUCCEEDED(rv)) {
  1.2514 +          aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
  1.2515 +        }
  1.2516 +      }
  1.2517 +    }
  1.2518 +    break;
  1.2519 +
  1.2520 +  default:
  1.2521 +    // switch not in sync with the optimization switch earlier in this function
  1.2522 +    NS_NOTREACHED("switch statements not in sync");
  1.2523 +    return NS_ERROR_UNEXPECTED;
  1.2524 +  }
  1.2525 +
  1.2526 +  return rv;
  1.2527 +}
  1.2528 +
  1.2529 +void
  1.2530 +Element::GetLinkTarget(nsAString& aTarget)
  1.2531 +{
  1.2532 +  aTarget.Truncate();
  1.2533 +}
  1.2534 +
  1.2535 +bool
  1.2536 +Element::MozMatchesSelector(const nsAString& aSelector,
  1.2537 +                            ErrorResult& aError)
  1.2538 +{
  1.2539 +  nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aError);
  1.2540 +  if (!selectorList) {
  1.2541 +    // Either we failed (and aError already has the exception), or this
  1.2542 +    // is a pseudo-element-only selector that matches nothing.
  1.2543 +    return false;
  1.2544 +  }
  1.2545 +
  1.2546 +  OwnerDoc()->FlushPendingLinkUpdates();
  1.2547 +  TreeMatchContext matchingContext(false,
  1.2548 +                                   nsRuleWalker::eRelevantLinkUnvisited,
  1.2549 +                                   OwnerDoc(),
  1.2550 +                                   TreeMatchContext::eNeverMatchVisited);
  1.2551 +  matchingContext.SetHasSpecifiedScope();
  1.2552 +  matchingContext.AddScopeElement(this);
  1.2553 +  return nsCSSRuleProcessor::SelectorListMatches(this, matchingContext,
  1.2554 +                                                 selectorList);
  1.2555 +}
  1.2556 +
  1.2557 +static const nsAttrValue::EnumTable kCORSAttributeTable[] = {
  1.2558 +  // Order matters here
  1.2559 +  // See ParseCORSValue
  1.2560 +  { "anonymous",       CORS_ANONYMOUS       },
  1.2561 +  { "use-credentials", CORS_USE_CREDENTIALS },
  1.2562 +  { 0 }
  1.2563 +};
  1.2564 +
  1.2565 +/* static */ void
  1.2566 +Element::ParseCORSValue(const nsAString& aValue,
  1.2567 +                        nsAttrValue& aResult)
  1.2568 +{
  1.2569 +  DebugOnly<bool> success =
  1.2570 +    aResult.ParseEnumValue(aValue, kCORSAttributeTable, false,
  1.2571 +                           // default value is anonymous if aValue is
  1.2572 +                           // not a value we understand
  1.2573 +                           &kCORSAttributeTable[0]);
  1.2574 +  MOZ_ASSERT(success);
  1.2575 +}
  1.2576 +
  1.2577 +/* static */ CORSMode
  1.2578 +Element::StringToCORSMode(const nsAString& aValue)
  1.2579 +{
  1.2580 +  if (aValue.IsVoid()) {
  1.2581 +    return CORS_NONE;
  1.2582 +  }
  1.2583 +
  1.2584 +  nsAttrValue val;
  1.2585 +  Element::ParseCORSValue(aValue, val);
  1.2586 +  return CORSMode(val.GetEnumValue());
  1.2587 +}
  1.2588 +
  1.2589 +/* static */ CORSMode
  1.2590 +Element::AttrValueToCORSMode(const nsAttrValue* aValue)
  1.2591 +{
  1.2592 +  if (!aValue) {
  1.2593 +    return CORS_NONE;
  1.2594 +  }
  1.2595 +
  1.2596 +  return CORSMode(aValue->GetEnumValue());
  1.2597 +}
  1.2598 +
  1.2599 +static const char*
  1.2600 +GetFullScreenError(nsIDocument* aDoc)
  1.2601 +{
  1.2602 +  // Block fullscreen requests in the chrome document when the fullscreen API
  1.2603 +  // is configured for content only.
  1.2604 +  if (nsContentUtils::IsFullscreenApiContentOnly() &&
  1.2605 +      nsContentUtils::IsChromeDoc(aDoc)) {
  1.2606 +    return "FullScreenDeniedContentOnly";
  1.2607 +  }
  1.2608 +
  1.2609 +  nsCOMPtr<nsPIDOMWindow> win = aDoc->GetWindow();
  1.2610 +  if (aDoc->NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED) {
  1.2611 +    // Request is in a web app and in the same origin as the web app.
  1.2612 +    // Don't enforce as strict security checks for web apps, the user
  1.2613 +    // is supposed to have trust in them. However documents cross-origin
  1.2614 +    // to the web app must still confirm to the normal security checks.
  1.2615 +    return nullptr;
  1.2616 +  }
  1.2617 +
  1.2618 +  if (!nsContentUtils::IsRequestFullScreenAllowed()) {
  1.2619 +    return "FullScreenDeniedNotInputDriven";
  1.2620 +  }
  1.2621 +
  1.2622 +  if (nsContentUtils::IsSitePermDeny(aDoc->NodePrincipal(), "fullscreen")) {
  1.2623 +    return "FullScreenDeniedBlocked";
  1.2624 +  }
  1.2625 +
  1.2626 +  return nullptr;
  1.2627 +}
  1.2628 +
  1.2629 +void
  1.2630 +Element::MozRequestFullScreen()
  1.2631 +{
  1.2632 +  // Only grant full-screen requests if this is called from inside a trusted
  1.2633 +  // event handler (i.e. inside an event handler for a user initiated event).
  1.2634 +  // This stops the full-screen from being abused similar to the popups of old,
  1.2635 +  // and it also makes it harder for bad guys' script to go full-screen and
  1.2636 +  // spoof the browser chrome/window and phish logins etc.
  1.2637 +  // Note that requests for fullscreen inside a web app's origin are exempt
  1.2638 +  // from this restriction.
  1.2639 +  const char* error = GetFullScreenError(OwnerDoc());
  1.2640 +  if (error) {
  1.2641 +    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
  1.2642 +                                    NS_LITERAL_CSTRING("DOM"), OwnerDoc(),
  1.2643 +                                    nsContentUtils::eDOM_PROPERTIES,
  1.2644 +                                    error);
  1.2645 +    nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
  1.2646 +      new AsyncEventDispatcher(OwnerDoc(),
  1.2647 +                               NS_LITERAL_STRING("mozfullscreenerror"),
  1.2648 +                               true,
  1.2649 +                               false);
  1.2650 +    asyncDispatcher->PostDOMEvent();
  1.2651 +    return;
  1.2652 +  }
  1.2653 +
  1.2654 +  OwnerDoc()->AsyncRequestFullScreen(this);
  1.2655 +
  1.2656 +  return;
  1.2657 +}
  1.2658 +
  1.2659 +void
  1.2660 +Element::MozRequestPointerLock()
  1.2661 +{
  1.2662 +  OwnerDoc()->RequestPointerLock(this);
  1.2663 +}
  1.2664 +
  1.2665 +NS_IMETHODIMP
  1.2666 +Element::GetInnerHTML(nsAString& aInnerHTML)
  1.2667 +{
  1.2668 +  GetMarkup(false, aInnerHTML);
  1.2669 +  return NS_OK;
  1.2670 +}
  1.2671 +
  1.2672 +void
  1.2673 +Element::SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
  1.2674 +{
  1.2675 +  SetInnerHTMLInternal(aInnerHTML, aError);
  1.2676 +}
  1.2677 +
  1.2678 +void
  1.2679 +Element::GetOuterHTML(nsAString& aOuterHTML)
  1.2680 +{
  1.2681 +  GetMarkup(true, aOuterHTML);
  1.2682 +}
  1.2683 +
  1.2684 +void
  1.2685 +Element::SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError)
  1.2686 +{
  1.2687 +  nsCOMPtr<nsINode> parent = GetParentNode();
  1.2688 +  if (!parent) {
  1.2689 +    return;
  1.2690 +  }
  1.2691 +
  1.2692 +  if (parent->NodeType() == nsIDOMNode::DOCUMENT_NODE) {
  1.2693 +    aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
  1.2694 +    return;
  1.2695 +  }
  1.2696 +
  1.2697 +  if (OwnerDoc()->IsHTML()) {
  1.2698 +    nsIAtom* localName;
  1.2699 +    int32_t namespaceID;
  1.2700 +    if (parent->IsElement()) {
  1.2701 +      localName = static_cast<nsIContent*>(parent.get())->Tag();
  1.2702 +      namespaceID = static_cast<nsIContent*>(parent.get())->GetNameSpaceID();
  1.2703 +    } else {
  1.2704 +      NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
  1.2705 +        "How come the parent isn't a document, a fragment or an element?");
  1.2706 +      localName = nsGkAtoms::body;
  1.2707 +      namespaceID = kNameSpaceID_XHTML;
  1.2708 +    }
  1.2709 +    nsRefPtr<DocumentFragment> fragment =
  1.2710 +      new DocumentFragment(OwnerDoc()->NodeInfoManager());
  1.2711 +    nsContentUtils::ParseFragmentHTML(aOuterHTML,
  1.2712 +                                      fragment,
  1.2713 +                                      localName,
  1.2714 +                                      namespaceID,
  1.2715 +                                      OwnerDoc()->GetCompatibilityMode() ==
  1.2716 +                                        eCompatibility_NavQuirks,
  1.2717 +                                      true);
  1.2718 +    parent->ReplaceChild(*fragment, *this, aError);
  1.2719 +    return;
  1.2720 +  }
  1.2721 +
  1.2722 +  nsCOMPtr<nsINode> context;
  1.2723 +  if (parent->IsElement()) {
  1.2724 +    context = parent;
  1.2725 +  } else {
  1.2726 +    NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
  1.2727 +      "How come the parent isn't a document, a fragment or an element?");
  1.2728 +    nsCOMPtr<nsINodeInfo> info =
  1.2729 +      OwnerDoc()->NodeInfoManager()->GetNodeInfo(nsGkAtoms::body,
  1.2730 +                                                 nullptr,
  1.2731 +                                                 kNameSpaceID_XHTML,
  1.2732 +                                                 nsIDOMNode::ELEMENT_NODE);
  1.2733 +    context = NS_NewHTMLBodyElement(info.forget(), FROM_PARSER_FRAGMENT);
  1.2734 +  }
  1.2735 +
  1.2736 +  nsCOMPtr<nsIDOMDocumentFragment> df;
  1.2737 +  aError = nsContentUtils::CreateContextualFragment(context,
  1.2738 +                                                    aOuterHTML,
  1.2739 +                                                    true,
  1.2740 +                                                    getter_AddRefs(df));
  1.2741 +  if (aError.Failed()) {
  1.2742 +    return;
  1.2743 +  }
  1.2744 +  nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
  1.2745 +  parent->ReplaceChild(*fragment, *this, aError);
  1.2746 +}
  1.2747 +
  1.2748 +enum nsAdjacentPosition {
  1.2749 +  eBeforeBegin,
  1.2750 +  eAfterBegin,
  1.2751 +  eBeforeEnd,
  1.2752 +  eAfterEnd
  1.2753 +};
  1.2754 +
  1.2755 +void
  1.2756 +Element::InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
  1.2757 +                            ErrorResult& aError)
  1.2758 +{
  1.2759 +  nsAdjacentPosition position;
  1.2760 +  if (aPosition.LowerCaseEqualsLiteral("beforebegin")) {
  1.2761 +    position = eBeforeBegin;
  1.2762 +  } else if (aPosition.LowerCaseEqualsLiteral("afterbegin")) {
  1.2763 +    position = eAfterBegin;
  1.2764 +  } else if (aPosition.LowerCaseEqualsLiteral("beforeend")) {
  1.2765 +    position = eBeforeEnd;
  1.2766 +  } else if (aPosition.LowerCaseEqualsLiteral("afterend")) {
  1.2767 +    position = eAfterEnd;
  1.2768 +  } else {
  1.2769 +    aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  1.2770 +    return;
  1.2771 +  }
  1.2772 +
  1.2773 +  nsCOMPtr<nsIContent> destination;
  1.2774 +  if (position == eBeforeBegin || position == eAfterEnd) {
  1.2775 +    destination = GetParent();
  1.2776 +    if (!destination) {
  1.2777 +      aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
  1.2778 +      return;
  1.2779 +    }
  1.2780 +  } else {
  1.2781 +    destination = this;
  1.2782 +  }
  1.2783 +
  1.2784 +  nsIDocument* doc = OwnerDoc();
  1.2785 +
  1.2786 +  // Needed when insertAdjacentHTML is used in combination with contenteditable
  1.2787 +  mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
  1.2788 +  nsAutoScriptLoaderDisabler sld(doc);
  1.2789 +  
  1.2790 +  // Batch possible DOMSubtreeModified events.
  1.2791 +  mozAutoSubtreeModified subtree(doc, nullptr);
  1.2792 +
  1.2793 +  // Parse directly into destination if possible
  1.2794 +  if (doc->IsHTML() && !OwnerDoc()->MayHaveDOMMutationObservers() &&
  1.2795 +      (position == eBeforeEnd ||
  1.2796 +       (position == eAfterEnd && !GetNextSibling()) ||
  1.2797 +       (position == eAfterBegin && !GetFirstChild()))) {
  1.2798 +    int32_t oldChildCount = destination->GetChildCount();
  1.2799 +    int32_t contextNs = destination->GetNameSpaceID();
  1.2800 +    nsIAtom* contextLocal = destination->Tag();
  1.2801 +    if (contextLocal == nsGkAtoms::html && contextNs == kNameSpaceID_XHTML) {
  1.2802 +      // For compat with IE6 through IE9. Willful violation of HTML5 as of
  1.2803 +      // 2011-04-06. CreateContextualFragment does the same already.
  1.2804 +      // Spec bug: http://www.w3.org/Bugs/Public/show_bug.cgi?id=12434
  1.2805 +      contextLocal = nsGkAtoms::body;
  1.2806 +    }
  1.2807 +    aError = nsContentUtils::ParseFragmentHTML(aText,
  1.2808 +                                               destination,
  1.2809 +                                               contextLocal,
  1.2810 +                                               contextNs,
  1.2811 +                                               doc->GetCompatibilityMode() ==
  1.2812 +                                                 eCompatibility_NavQuirks,
  1.2813 +                                               true);
  1.2814 +    // HTML5 parser has notified, but not fired mutation events.
  1.2815 +    nsContentUtils::FireMutationEventsForDirectParsing(doc, destination,
  1.2816 +                                                       oldChildCount);
  1.2817 +    return;
  1.2818 +  }
  1.2819 +
  1.2820 +  // couldn't parse directly
  1.2821 +  nsCOMPtr<nsIDOMDocumentFragment> df;
  1.2822 +  aError = nsContentUtils::CreateContextualFragment(destination,
  1.2823 +                                                    aText,
  1.2824 +                                                    true,
  1.2825 +                                                    getter_AddRefs(df));
  1.2826 +  if (aError.Failed()) {
  1.2827 +    return;
  1.2828 +  }
  1.2829 +
  1.2830 +  nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
  1.2831 +
  1.2832 +  // Suppress assertion about node removal mutation events that can't have
  1.2833 +  // listeners anyway, because no one has had the chance to register mutation
  1.2834 +  // listeners on the fragment that comes from the parser.
  1.2835 +  nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
  1.2836 +
  1.2837 +  nsAutoMutationBatch mb(destination, true, false);
  1.2838 +  switch (position) {
  1.2839 +    case eBeforeBegin:
  1.2840 +      destination->InsertBefore(*fragment, this, aError);
  1.2841 +      break;
  1.2842 +    case eAfterBegin:
  1.2843 +      static_cast<nsINode*>(this)->InsertBefore(*fragment, GetFirstChild(),
  1.2844 +                                                aError);
  1.2845 +      break;
  1.2846 +    case eBeforeEnd:
  1.2847 +      static_cast<nsINode*>(this)->AppendChild(*fragment, aError);
  1.2848 +      break;
  1.2849 +    case eAfterEnd:
  1.2850 +      destination->InsertBefore(*fragment, GetNextSibling(), aError);
  1.2851 +      break;
  1.2852 +  }
  1.2853 +}
  1.2854 +
  1.2855 +nsIEditor*
  1.2856 +Element::GetEditorInternal()
  1.2857 +{
  1.2858 +  nsCOMPtr<nsITextControlElement> textCtrl = do_QueryInterface(this);
  1.2859 +  return textCtrl ? textCtrl->GetTextEditor() : nullptr;
  1.2860 +}
  1.2861 +
  1.2862 +nsresult
  1.2863 +Element::SetBoolAttr(nsIAtom* aAttr, bool aValue)
  1.2864 +{
  1.2865 +  if (aValue) {
  1.2866 +    return SetAttr(kNameSpaceID_None, aAttr, EmptyString(), true);
  1.2867 +  }
  1.2868 +
  1.2869 +  return UnsetAttr(kNameSpaceID_None, aAttr, true);
  1.2870 +}
  1.2871 +
  1.2872 +Directionality
  1.2873 +Element::GetComputedDirectionality() const
  1.2874 +{
  1.2875 +  nsIFrame* frame = GetPrimaryFrame();
  1.2876 +  if (frame) {
  1.2877 +    return frame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR
  1.2878 +             ? eDir_LTR : eDir_RTL;
  1.2879 +  }
  1.2880 +
  1.2881 +  return GetDirectionality();
  1.2882 +}
  1.2883 +
  1.2884 +float
  1.2885 +Element::FontSizeInflation()
  1.2886 +{
  1.2887 +  nsIFrame* frame = GetPrimaryFrame();
  1.2888 +  if (!frame) {
  1.2889 +    return -1.0;
  1.2890 +  }
  1.2891 +
  1.2892 +  if (nsLayoutUtils::FontSizeInflationEnabled(frame->PresContext())) {
  1.2893 +    return nsLayoutUtils::FontSizeInflationFor(frame);
  1.2894 +  }
  1.2895 +
  1.2896 +  return 1.0;
  1.2897 +}

mercurial