mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			537 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			537 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "mozilla/dom/ElementInternals.h"
 | 
						|
 | 
						|
#include "mozAutoDocUpdate.h"
 | 
						|
#include "mozilla/dom/CustomElementRegistry.h"
 | 
						|
#include "mozilla/dom/CustomEvent.h"
 | 
						|
#include "mozilla/dom/CustomStateSet.h"
 | 
						|
#include "mozilla/dom/ElementInternalsBinding.h"
 | 
						|
#include "mozilla/dom/FormData.h"
 | 
						|
#include "mozilla/dom/HTMLElement.h"
 | 
						|
#include "mozilla/dom/HTMLFieldSetElement.h"
 | 
						|
#include "mozilla/dom/MutationEventBinding.h"
 | 
						|
#include "mozilla/dom/MutationObservers.h"
 | 
						|
#include "mozilla/dom/ShadowRoot.h"
 | 
						|
#include "mozilla/dom/ValidityState.h"
 | 
						|
#include "nsContentUtils.h"
 | 
						|
#include "nsDebug.h"
 | 
						|
#include "nsGenericHTMLElement.h"
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
#  include "nsAccessibilityService.h"
 | 
						|
#endif
 | 
						|
 | 
						|
namespace mozilla::dom {
 | 
						|
 | 
						|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ElementInternals)
 | 
						|
 | 
						|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ElementInternals)
 | 
						|
  tmp->Unlink();
 | 
						|
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTarget, mSubmissionValue, mState, mValidity,
 | 
						|
                                  mValidationAnchor, mCustomStateSet);
 | 
						|
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 | 
						|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 | 
						|
 | 
						|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ElementInternals)
 | 
						|
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTarget, mSubmissionValue, mState,
 | 
						|
                                    mValidity, mValidationAnchor,
 | 
						|
                                    mCustomStateSet);
 | 
						|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 | 
						|
 | 
						|
NS_IMPL_CYCLE_COLLECTING_ADDREF(ElementInternals)
 | 
						|
NS_IMPL_CYCLE_COLLECTING_RELEASE(ElementInternals)
 | 
						|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ElementInternals)
 | 
						|
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 | 
						|
  NS_INTERFACE_MAP_ENTRY(nsIFormControl)
 | 
						|
  NS_INTERFACE_MAP_ENTRY(nsIConstraintValidation)
 | 
						|
NS_INTERFACE_MAP_END
 | 
						|
 | 
						|
ElementInternals::ElementInternals(HTMLElement* aTarget)
 | 
						|
    : nsIFormControl(FormControlType::FormAssociatedCustomElement),
 | 
						|
      mTarget(aTarget),
 | 
						|
      mForm(nullptr),
 | 
						|
      mFieldSet(nullptr),
 | 
						|
      mControlNumber(-1) {}
 | 
						|
 | 
						|
nsISupports* ElementInternals::GetParentObject() { return ToSupports(mTarget); }
 | 
						|
 | 
						|
JSObject* ElementInternals::WrapObject(JSContext* aCx,
 | 
						|
                                       JS::Handle<JSObject*> aGivenProto) {
 | 
						|
  return ElementInternals_Binding::Wrap(aCx, this, aGivenProto);
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/#dom-elementinternals-shadowroot
 | 
						|
ShadowRoot* ElementInternals::GetShadowRoot() const {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  ShadowRoot* shadowRoot = mTarget->GetShadowRoot();
 | 
						|
  if (shadowRoot && !shadowRoot->IsAvailableToElementInternals()) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  return shadowRoot;
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/commit-snapshots/912a3fe1f29649ccf8229de56f604b3c07ffd242/#dom-elementinternals-setformvalue
 | 
						|
void ElementInternals::SetFormValue(
 | 
						|
    const Nullable<FileOrUSVStringOrFormData>& aValue,
 | 
						|
    const Optional<Nullable<FileOrUSVStringOrFormData>>& aState,
 | 
						|
    ErrorResult& aRv) {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  /**
 | 
						|
   * 1. Let element be this's target element.
 | 
						|
   * 2. If element is not a form-associated custom element, then throw a
 | 
						|
   *    "NotSupportedError" DOMException.
 | 
						|
   */
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 3. Set target element's submission value to value if value is not a
 | 
						|
   *    FormData object, or to a clone of the entry list associated with value
 | 
						|
   *    otherwise.
 | 
						|
   */
 | 
						|
  mSubmissionValue.SetNull();
 | 
						|
  if (!aValue.IsNull()) {
 | 
						|
    const FileOrUSVStringOrFormData& value = aValue.Value();
 | 
						|
    OwningFileOrUSVStringOrFormData& owningValue = mSubmissionValue.SetValue();
 | 
						|
    if (value.IsFormData()) {
 | 
						|
      owningValue.SetAsFormData() = value.GetAsFormData().Clone();
 | 
						|
    } else if (value.IsFile()) {
 | 
						|
      owningValue.SetAsFile() = &value.GetAsFile();
 | 
						|
    } else {
 | 
						|
      owningValue.SetAsUSVString() = value.GetAsUSVString();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 4. If the state argument of the function is omitted, set element's state to
 | 
						|
   *    its submission value.
 | 
						|
   */
 | 
						|
  if (!aState.WasPassed()) {
 | 
						|
    mState = mSubmissionValue;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 5. Otherwise, if state is a FormData object, set element's state to clone
 | 
						|
   *    of the entry list associated with state.
 | 
						|
   * 6. Otherwise, set element's state to state.
 | 
						|
   */
 | 
						|
  mState.SetNull();
 | 
						|
  if (!aState.Value().IsNull()) {
 | 
						|
    const FileOrUSVStringOrFormData& state = aState.Value().Value();
 | 
						|
    OwningFileOrUSVStringOrFormData& owningState = mState.SetValue();
 | 
						|
    if (state.IsFormData()) {
 | 
						|
      owningState.SetAsFormData() = state.GetAsFormData().Clone();
 | 
						|
    } else if (state.IsFile()) {
 | 
						|
      owningState.SetAsFile() = &state.GetAsFile();
 | 
						|
    } else {
 | 
						|
      owningState.SetAsUSVString() = state.GetAsUSVString();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/#dom-elementinternals-form
 | 
						|
HTMLFormElement* ElementInternals::GetForm(ErrorResult& aRv) const {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  return GetForm();
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/commit-snapshots/3ad5159be8f27e110a70cefadcb50fc45ec21b05/#dom-elementinternals-setvalidity
 | 
						|
void ElementInternals::SetValidity(
 | 
						|
    const ValidityStateFlags& aFlags, const Optional<nsAString>& aMessage,
 | 
						|
    const Optional<NonNull<nsGenericHTMLElement>>& aAnchor, ErrorResult& aRv) {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  /**
 | 
						|
   * 1. Let element be this's target element.
 | 
						|
   * 2. If element is not a form-associated custom element, then throw a
 | 
						|
   *    "NotSupportedError" DOMException.
 | 
						|
   */
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 3. If flags contains one or more true values and message is not given or is
 | 
						|
   *    the empty string, then throw a TypeError.
 | 
						|
   */
 | 
						|
  if ((aFlags.mBadInput || aFlags.mCustomError || aFlags.mPatternMismatch ||
 | 
						|
       aFlags.mRangeOverflow || aFlags.mRangeUnderflow ||
 | 
						|
       aFlags.mStepMismatch || aFlags.mTooLong || aFlags.mTooShort ||
 | 
						|
       aFlags.mTypeMismatch || aFlags.mValueMissing) &&
 | 
						|
      (!aMessage.WasPassed() || aMessage.Value().IsEmpty())) {
 | 
						|
    aRv.ThrowTypeError("Need to provide validation message");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 4. For each entry flag → value of flags, set element's validity flag with
 | 
						|
   *    the name flag to value.
 | 
						|
   */
 | 
						|
  SetValidityState(VALIDITY_STATE_VALUE_MISSING, aFlags.mValueMissing);
 | 
						|
  SetValidityState(VALIDITY_STATE_TYPE_MISMATCH, aFlags.mTypeMismatch);
 | 
						|
  SetValidityState(VALIDITY_STATE_PATTERN_MISMATCH, aFlags.mPatternMismatch);
 | 
						|
  SetValidityState(VALIDITY_STATE_TOO_LONG, aFlags.mTooLong);
 | 
						|
  SetValidityState(VALIDITY_STATE_TOO_SHORT, aFlags.mTooShort);
 | 
						|
  SetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW, aFlags.mRangeUnderflow);
 | 
						|
  SetValidityState(VALIDITY_STATE_RANGE_OVERFLOW, aFlags.mRangeOverflow);
 | 
						|
  SetValidityState(VALIDITY_STATE_STEP_MISMATCH, aFlags.mStepMismatch);
 | 
						|
  SetValidityState(VALIDITY_STATE_BAD_INPUT, aFlags.mBadInput);
 | 
						|
  SetValidityState(VALIDITY_STATE_CUSTOM_ERROR, aFlags.mCustomError);
 | 
						|
  mTarget->UpdateValidityElementStates(true);
 | 
						|
 | 
						|
  /**
 | 
						|
   * 5. Set element's validation message to the empty string if message is not
 | 
						|
   *    given or all of element's validity flags are false, or to message
 | 
						|
   *    otherwise.
 | 
						|
   * 6. If element's customError validity flag is true, then set element's
 | 
						|
   *    custom validity error message to element's validation message.
 | 
						|
   *    Otherwise, set element's custom validity error message to the empty
 | 
						|
   *    string.
 | 
						|
   */
 | 
						|
  mValidationMessage =
 | 
						|
      (!aMessage.WasPassed() || IsValid()) ? EmptyString() : aMessage.Value();
 | 
						|
 | 
						|
  /**
 | 
						|
   * 7. Set element's validation anchor to null if anchor is not given.
 | 
						|
   *    Otherwise, if anchor is not a shadow-including descendant of element,
 | 
						|
   *    then throw a "NotFoundError" DOMException. Otherwise, set element's
 | 
						|
   *    validation anchor to anchor.
 | 
						|
   */
 | 
						|
  nsGenericHTMLElement* anchor =
 | 
						|
      aAnchor.WasPassed() ? &aAnchor.Value() : nullptr;
 | 
						|
  // TODO: maybe create something like IsShadowIncludingDescendantOf if there
 | 
						|
  //       are other places also need such check.
 | 
						|
  if (anchor && (anchor == mTarget ||
 | 
						|
                 !anchor->IsShadowIncludingInclusiveDescendantOf(mTarget))) {
 | 
						|
    aRv.ThrowNotFoundError(
 | 
						|
        "Validation anchor is not a shadow-including descendant of target"
 | 
						|
        "element");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  mValidationAnchor = anchor;
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/#dom-elementinternals-willvalidate
 | 
						|
bool ElementInternals::GetWillValidate(ErrorResult& aRv) const {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return WillValidate();
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/#dom-elementinternals-validity
 | 
						|
ValidityState* ElementInternals::GetValidity(ErrorResult& aRv) {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  return Validity();
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/#dom-elementinternals-validationmessage
 | 
						|
void ElementInternals::GetValidationMessage(nsAString& aValidationMessage,
 | 
						|
                                            ErrorResult& aRv) const {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  aValidationMessage = mValidationMessage;
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/#dom-elementinternals-checkvalidity
 | 
						|
bool ElementInternals::CheckValidity(ErrorResult& aRv) {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return nsIConstraintValidation::CheckValidity(*mTarget);
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/#dom-elementinternals-reportvalidity
 | 
						|
bool ElementInternals::ReportValidity(ErrorResult& aRv) {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  bool defaultAction = true;
 | 
						|
  if (nsIConstraintValidation::CheckValidity(*mTarget, &defaultAction)) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!defaultAction) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  AutoTArray<RefPtr<Element>, 1> invalidElements;
 | 
						|
  invalidElements.AppendElement(mTarget);
 | 
						|
 | 
						|
  AutoJSAPI jsapi;
 | 
						|
  if (!jsapi.Init(mTarget->GetOwnerGlobal())) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  JS::Rooted<JS::Value> detail(jsapi.cx());
 | 
						|
  if (!ToJSValue(jsapi.cx(), invalidElements, &detail)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<CustomEvent> event =
 | 
						|
      NS_NewDOMCustomEvent(mTarget->OwnerDoc(), nullptr, nullptr);
 | 
						|
  event->InitCustomEvent(jsapi.cx(), u"MozInvalidForm"_ns,
 | 
						|
                         /* CanBubble */ true,
 | 
						|
                         /* Cancelable */ true, detail);
 | 
						|
  event->SetTrusted(true);
 | 
						|
  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
 | 
						|
  mTarget->DispatchEvent(*event);
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
// https://html.spec.whatwg.org/#dom-elementinternals-labels
 | 
						|
already_AddRefed<nsINodeList> ElementInternals::GetLabels(
 | 
						|
    ErrorResult& aRv) const {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  return mTarget->Labels();
 | 
						|
}
 | 
						|
 | 
						|
nsGenericHTMLElement* ElementInternals::GetValidationAnchor(
 | 
						|
    ErrorResult& aRv) const {
 | 
						|
  MOZ_ASSERT(mTarget);
 | 
						|
 | 
						|
  if (!mTarget->IsFormAssociatedElement()) {
 | 
						|
    aRv.ThrowNotSupportedError(
 | 
						|
        "Target element is not a form-associated custom element");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  return mValidationAnchor;
 | 
						|
}
 | 
						|
 | 
						|
CustomStateSet* ElementInternals::States() {
 | 
						|
  if (!mCustomStateSet) {
 | 
						|
    mCustomStateSet = new CustomStateSet(mTarget);
 | 
						|
  }
 | 
						|
  return mCustomStateSet;
 | 
						|
}
 | 
						|
 | 
						|
void ElementInternals::SetForm(HTMLFormElement* aForm) { mForm = aForm; }
 | 
						|
 | 
						|
void ElementInternals::ClearForm(bool aRemoveFromForm, bool aUnbindOrDelete) {
 | 
						|
  if (mTarget) {
 | 
						|
    mTarget->ClearForm(aRemoveFromForm, aUnbindOrDelete);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP ElementInternals::Reset() {
 | 
						|
  if (mTarget) {
 | 
						|
    MOZ_ASSERT(mTarget->IsFormAssociatedElement());
 | 
						|
    nsContentUtils::EnqueueLifecycleCallback(ElementCallbackType::eFormReset,
 | 
						|
                                             mTarget, {});
 | 
						|
  }
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP ElementInternals::SubmitNamesValues(FormData* aFormData) {
 | 
						|
  if (!mTarget) {
 | 
						|
    return NS_ERROR_UNEXPECTED;
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(mTarget->IsFormAssociatedElement());
 | 
						|
 | 
						|
  // https://html.spec.whatwg.org/#face-entry-construction
 | 
						|
  if (!mSubmissionValue.IsNull()) {
 | 
						|
    if (mSubmissionValue.Value().IsFormData()) {
 | 
						|
      aFormData->Append(mSubmissionValue.Value().GetAsFormData());
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
 | 
						|
    // Get the name
 | 
						|
    nsAutoString name;
 | 
						|
    if (!mTarget->GetAttr(nsGkAtoms::name, name) || name.IsEmpty()) {
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
 | 
						|
    if (mSubmissionValue.Value().IsUSVString()) {
 | 
						|
      return aFormData->AddNameValuePair(
 | 
						|
          name, mSubmissionValue.Value().GetAsUSVString());
 | 
						|
    }
 | 
						|
 | 
						|
    return aFormData->AddNameBlobPair(name,
 | 
						|
                                      mSubmissionValue.Value().GetAsFile());
 | 
						|
  }
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
void ElementInternals::UpdateFormOwner() {
 | 
						|
  if (mTarget) {
 | 
						|
    mTarget->UpdateFormOwner();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ElementInternals::UpdateBarredFromConstraintValidation() {
 | 
						|
  if (mTarget) {
 | 
						|
    MOZ_ASSERT(mTarget->IsFormAssociatedElement());
 | 
						|
    SetBarredFromConstraintValidation(
 | 
						|
        mTarget->IsDisabled() || mTarget->HasAttr(nsGkAtoms::readonly) ||
 | 
						|
        mTarget->HasFlag(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ElementInternals::Unlink() {
 | 
						|
  if (mForm) {
 | 
						|
    // Don't notify, since we're being destroyed in any case.
 | 
						|
    ClearForm(true, true);
 | 
						|
    MOZ_DIAGNOSTIC_ASSERT(!mForm);
 | 
						|
  }
 | 
						|
  if (mFieldSet) {
 | 
						|
    mFieldSet->RemoveElement(mTarget);
 | 
						|
    mFieldSet = nullptr;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ElementInternals::GetAttr(const nsAtom* aName, nsAString& aResult) const {
 | 
						|
  MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in");
 | 
						|
 | 
						|
  const nsAttrValue* val = mAttrs.GetAttr(aName);
 | 
						|
  if (val) {
 | 
						|
    val->ToString(aResult);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  SetDOMStringToNull(aResult);
 | 
						|
}
 | 
						|
 | 
						|
nsresult ElementInternals::SetAttr(nsAtom* aName, const nsAString& aValue) {
 | 
						|
  Document* document = mTarget->GetComposedDoc();
 | 
						|
  mozAutoDocUpdate updateBatch(document, true);
 | 
						|
 | 
						|
  uint8_t modType = mAttrs.HasAttr(aName) ? MutationEvent_Binding::MODIFICATION
 | 
						|
                                          : MutationEvent_Binding::ADDITION;
 | 
						|
 | 
						|
  MutationObservers::NotifyARIAAttributeDefaultWillChange(mTarget, aName,
 | 
						|
                                                          modType);
 | 
						|
 | 
						|
  nsAttrValue attrValue(aValue);
 | 
						|
  nsresult rs = NS_OK;
 | 
						|
  if (DOMStringIsNull(aValue)) {
 | 
						|
    auto attrPos = mAttrs.IndexOfAttr(aName);
 | 
						|
    if (attrPos >= 0) {
 | 
						|
      rs = mAttrs.RemoveAttrAt(attrPos, attrValue);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    bool attrHadValue = false;
 | 
						|
    rs = mAttrs.SetAndSwapAttr(aName, attrValue, &attrHadValue);
 | 
						|
  }
 | 
						|
  nsMutationGuard::DidMutate();
 | 
						|
 | 
						|
  MutationObservers::NotifyARIAAttributeDefaultChanged(mTarget, aName, modType);
 | 
						|
 | 
						|
  return rs;
 | 
						|
}
 | 
						|
 | 
						|
DocGroup* ElementInternals::GetDocGroup() {
 | 
						|
  return mTarget->OwnerDoc()->GetDocGroup();
 | 
						|
}
 | 
						|
 | 
						|
void ElementInternals::RestoreFormValue(
 | 
						|
    Nullable<OwningFileOrUSVStringOrFormData>&& aValue,
 | 
						|
    Nullable<OwningFileOrUSVStringOrFormData>&& aState) {
 | 
						|
  mSubmissionValue = aValue;
 | 
						|
  mState = aState;
 | 
						|
 | 
						|
  if (!mState.IsNull()) {
 | 
						|
    LifecycleCallbackArgs args;
 | 
						|
    args.mState = mState;
 | 
						|
    args.mReason = RestoreReason::Restore;
 | 
						|
    nsContentUtils::EnqueueLifecycleCallback(
 | 
						|
        ElementCallbackType::eFormStateRestore, mTarget, args);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ElementInternals::InitializeControlNumber() {
 | 
						|
  MOZ_ASSERT(mControlNumber == -1,
 | 
						|
             "FACE control number should only be initialized once!");
 | 
						|
  mControlNumber = mTarget->OwnerDoc()->GetNextControlNumber();
 | 
						|
}
 | 
						|
 | 
						|
void ElementInternals::SetAttrElement(nsAtom* aAttr, Element* aElement) {
 | 
						|
  // Accessibility requires that no other attribute changes occur between
 | 
						|
  // AttrElementWillChange and AttrElementChanged. Scripts could cause
 | 
						|
  // this, so don't let them run here. We do this even if accessibility isn't
 | 
						|
  // running so that the JS behavior is consistent regardless of accessibility.
 | 
						|
  // Otherwise, JS might be able to use this difference to determine whether
 | 
						|
  // accessibility is running, which would be a privacy concern.
 | 
						|
  nsAutoScriptBlocker scriptBlocker;
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  // If the target has this attribute defined then it overrides the defaults
 | 
						|
  // defined here in the Internals instance. In that case we don't need to
 | 
						|
  // notify the change to a11y since the attribute hasn't changed, just the
 | 
						|
  // underlying default. We can set accService to null and not notify.
 | 
						|
  nsAccessibilityService* accService =
 | 
						|
      !mTarget->HasAttr(aAttr) ? GetAccService() : nullptr;
 | 
						|
  if (accService) {
 | 
						|
    accService->NotifyAttrElementWillChange(mTarget, aAttr);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  if (aElement) {
 | 
						|
    mAttrElements.InsertOrUpdate(aAttr, do_GetWeakReference(aElement));
 | 
						|
  } else {
 | 
						|
    mAttrElements.Remove(aAttr);
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  if (accService) {
 | 
						|
    accService->NotifyAttrElementChanged(mTarget, aAttr);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
Element* ElementInternals::GetAttrElement(nsAtom* aAttr) const {
 | 
						|
  nsWeakPtr weakAttrEl = mAttrElements.Get(aAttr);
 | 
						|
  nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl);
 | 
						|
  return attrEl;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla::dom
 |