/* THIS FILE IS AUTOGENERATED FROM Animatable.webidl BY Codegen.py - DO NOT EDIT */

#include <type_traits>
#include "AnimatableBinding.h"
#include "AtomList.h"
#include "MainThreadUtils.h"
#include "TimelineRangeOffsetBinding.h"
#include "js/CallAndConstruct.h"
#include "js/Exception.h"
#include "js/MapAndSet.h"
#include "js/Object.h"
#include "js/PropertyAndElement.h"
#include "js/PropertyDescriptor.h"
#include "js/experimental/JitInfo.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/dom/BindingCallContext.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/CSSKeywordValue.h"
#include "mozilla/dom/CSSNumericValue.h"
#include "mozilla/dom/NonRefcountedDOMObject.h"
#include "mozilla/dom/PrimitiveConversions.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SimpleGlobalObject.h"

namespace mozilla::dom {

namespace binding_detail {}; // Just to make sure it's known as a namespace
using namespace mozilla::dom::binding_detail;


void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String& aUnion, const char* aName, uint32_t aFlags)
{
  if (aUnion.IsTimelineRangeOffset()) {
    ImplCycleCollectionTraverse(aCallback, aUnion.GetAsTimelineRangeOffset(), "mTimelineRangeOffset", aFlags);
  } else if (aUnion.IsCSSNumericValue()) {
    ImplCycleCollectionTraverse(aCallback, aUnion.GetAsCSSNumericValue(), "mCSSNumericValue", aFlags);
  } else if (aUnion.IsCSSKeywordValue()) {
    ImplCycleCollectionTraverse(aCallback, aUnion.GetAsCSSKeywordValue(), "mCSSKeywordValue", aFlags);
  }
}


void
ImplCycleCollectionUnlink(OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String& aUnion)
{
  aUnion.Uninit();
}



GetAnimationsOptions::GetAnimationsOptions()
{
  // Safe to pass a null context if we pass a null value
  Init(nullptr, JS::NullHandleValue);
}




bool
GetAnimationsOptions::InitIds(JSContext* cx, GetAnimationsOptionsAtoms* atomsCache)
{
  MOZ_ASSERT(reinterpret_cast<jsid*>(atomsCache)->isVoid());

  // Initialize these in reverse order so that any failure leaves the first one
  // uninitialized.
  if (!atomsCache->subtree_id.init(cx, "subtree") ||
      !atomsCache->pseudoElement_id.init(cx, "pseudoElement")) {
    return false;
  }
  return true;
}

bool
GetAnimationsOptions::Init(BindingCallContext& cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
{
  // Passing a null JSContext is OK only if we're initing from null,
  // Since in that case we will not have to do any property gets
  // Also evaluate isNullOrUndefined in order to avoid false-positive
  // checkers by static analysis tools
  MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
  GetAnimationsOptionsAtoms* atomsCache = nullptr;
  if (cx) {
    atomsCache = GetAtomCache<GetAnimationsOptionsAtoms>(cx);
    if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
        !InitIds(cx, atomsCache)) {
      return false;
    }
  }

  if (!IsConvertibleToDictionary(val)) {
    return cx.ThrowErrorMessage<MSG_CONVERSION_ERROR>(sourceDescription, "dictionary");
  }

  bool isNull = val.isNullOrUndefined();
  // We only need these if !isNull, in which case we have |cx|.
  Maybe<JS::Rooted<JSObject *> > object;
  Maybe<JS::Rooted<JS::Value> > temp;
  if (!isNull) {
    MOZ_ASSERT(cx);
    object.emplace(cx, &val.toObject());
    temp.emplace(cx);
  }
  if (!isNull) {
    if (!JS_GetPropertyById(cx, *object, atomsCache->pseudoElement_id, temp.ptr())) {
      return false;
    }
  }
  if (!isNull && !temp->isUndefined()) {
    if (!ConvertJSValueToString(cx, temp.ref(), eNull, eNull, mPseudoElement)) {
      return false;
    }
  } else {
    mPseudoElement.SetIsVoid(true);
  }
  mIsAnyMemberPresent = true;

  if (!isNull) {
    if (!JS_GetPropertyById(cx, *object, atomsCache->subtree_id, temp.ptr())) {
      return false;
    }
  }
  if (!isNull && !temp->isUndefined()) {
    if (!ValueToPrimitive<bool, eDefault>(cx, temp.ref(), "'subtree' member of GetAnimationsOptions", &mSubtree)) {
      return false;
    }
  } else {
    mSubtree = false;
  }
  mIsAnyMemberPresent = true;
  return true;
}

bool
GetAnimationsOptions::Init(JSContext* cx_, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
{
  // We don't want to use sourceDescription for our context here;
  // that's not really what it's formatted for.
  BindingCallContext cx(cx_, nullptr);
  return Init(cx, val, sourceDescription, passedToJSImpl);
}

void
GetAnimationsOptions::TraceDictionary(JSTracer* trc)
{
}

GetAnimationsOptions&
GetAnimationsOptions::operator=(const GetAnimationsOptions& aOther)
{
  MaybeEmptyDictionaryBase::operator=(aOther);
  mPseudoElement = aOther.mPseudoElement;
  mSubtree = aOther.mSubtree;
  return *this;
}


bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToTimelineRangeOffset(BindingCallContext& cx, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  tryNext = false;
  { // scope for memberSlot
    binding_detail::FastTimelineRangeOffset& memberSlot = RawSetAsTimelineRangeOffset();
    if (!IsConvertibleToDictionary(value)) {
      DestroyTimelineRangeOffset();
      tryNext = true;
      return true;
    }
    if (!memberSlot.Init(cx, value, "TimelineRangeOffset branch of (TimelineRangeOffset or CSSNumericValue or CSSKeywordValue or USVString)", passedToJSImpl)) {
      return false;
    }
  }
  return true;
}

bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToTimelineRangeOffset(JSContext* cx_, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  BindingCallContext cx(cx_, nullptr);
  return TrySetToTimelineRangeOffset(cx, value, tryNext, passedToJSImpl);
}







bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToCSSNumericValue(BindingCallContext& cx, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  tryNext = false;
  { // scope for memberSlot
    NonNull<mozilla::dom::CSSNumericValue>& memberSlot = RawSetAsCSSNumericValue();
    {
      // Our JSContext should be in the right global to do unwrapping in.
      nsresult rv = UnwrapObject<prototypes::id::CSSNumericValue, mozilla::dom::CSSNumericValue>(value, memberSlot, cx);
      if (NS_FAILED(rv)) {
        DestroyCSSNumericValue();
        tryNext = true;
        return true;
      }
    }
  }
  return true;
}

bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToCSSNumericValue(JSContext* cx_, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  BindingCallContext cx(cx_, nullptr);
  return TrySetToCSSNumericValue(cx, value, tryNext, passedToJSImpl);
}







bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToCSSKeywordValue(BindingCallContext& cx, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  tryNext = false;
  { // scope for memberSlot
    NonNull<mozilla::dom::CSSKeywordValue>& memberSlot = RawSetAsCSSKeywordValue();
    {
      // Our JSContext should be in the right global to do unwrapping in.
      nsresult rv = UnwrapObject<prototypes::id::CSSKeywordValue, mozilla::dom::CSSKeywordValue>(value, memberSlot, cx);
      if (NS_FAILED(rv)) {
        DestroyCSSKeywordValue();
        tryNext = true;
        return true;
      }
    }
  }
  return true;
}

bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToCSSKeywordValue(JSContext* cx_, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  BindingCallContext cx(cx_, nullptr);
  return TrySetToCSSKeywordValue(cx, value, tryNext, passedToJSImpl);
}







bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToUTF8String(JSContext* cx, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  tryNext = false;
  { // scope for memberSlot
    nsAutoCString& memberSlot = RawSetAsUTF8String();
    if (!ConvertJSValueToString(cx, value, eStringify, eStringify, memberSlot)) {
      return false;
    }
  }
  return true;
}








bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::Init(BindingCallContext& cx, JS::Handle<JS::Value> value, const char* sourceDescription, bool passedToJSImpl)
{
  MOZ_ASSERT(mType == eUninitialized);

  bool done = false, failed = false, tryNext;
  if (value.isObject()) {
    done = (failed = !TrySetToCSSNumericValue(cx, value, tryNext, passedToJSImpl)) || !tryNext ||
           (failed = !TrySetToCSSKeywordValue(cx, value, tryNext, passedToJSImpl)) || !tryNext;
  }
  if (!done) {
    done = (failed = !TrySetToTimelineRangeOffset(cx, value, tryNext, passedToJSImpl)) || !tryNext;
  }
  if (!done) {
    do {
      done = (failed = !TrySetToUTF8String(cx, value, tryNext)) || !tryNext;
      break;
    } while (false);
  }
  if (failed) {
    return false;
  }
  if (!done) {
    cx.ThrowErrorMessage<MSG_NOT_IN_UNION>(sourceDescription, "CSSNumericValue, CSSKeywordValue, TimelineRangeOffset");
    return false;
  }
  return true;
}

bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::Init(JSContext* cx_, JS::Handle<JS::Value> value, const char* sourceDescription, bool passedToJSImpl)
{
  BindingCallContext cx(cx_, nullptr);
  return Init(cx, value, sourceDescription, passedToJSImpl);
}


bool
TimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj, JS::MutableHandle<JS::Value> rval) const
{
  switch (mType) {
    case eUninitialized: {
      return false;
    }
    case eTimelineRangeOffset: {
      if (!mValue.mTimelineRangeOffset.Value().ToObjectInternal(cx, rval)) {
        return false;
      }
      return true;
    }
    case eCSSNumericValue: {
      if (!GetOrCreateDOMReflector(cx, mValue.mCSSNumericValue.Value(), rval)) {
        MOZ_ASSERT(JS_IsExceptionPending(cx));
        return false;
      }
      return true;
    }
    case eCSSKeywordValue: {
      if (!GetOrCreateDOMReflector(cx, mValue.mCSSKeywordValue.Value(), rval)) {
        MOZ_ASSERT(JS_IsExceptionPending(cx));
        return false;
      }
      return true;
    }
    case eUTF8String: {
      if (!NonVoidUTF8StringToJsval(cx, mValue.mUTF8String.Value(), rval)) {
        return false;
      }
      return true;
    }
    default: {
      return false;
    }
  }
}



OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String(OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String&& aOther)
  : mType(eUninitialized)
{
  switch (aOther.mType) {
    case eUninitialized: {
      MOZ_ASSERT(mType == eUninitialized,
                 "We need to destroy ourselves?");
      break;
    }
    case eTimelineRangeOffset: {
      mType = eTimelineRangeOffset;
      mValue.mTimelineRangeOffset.SetValue(std::move(aOther.mValue.mTimelineRangeOffset.Value()));
      break;
    }
    case eCSSNumericValue: {
      mType = eCSSNumericValue;
      mValue.mCSSNumericValue.SetValue(std::move(aOther.mValue.mCSSNumericValue.Value()));
      break;
    }
    case eCSSKeywordValue: {
      mType = eCSSKeywordValue;
      mValue.mCSSKeywordValue.SetValue(std::move(aOther.mValue.mCSSKeywordValue.Value()));
      break;
    }
    case eUTF8String: {
      mType = eUTF8String;
      mValue.mUTF8String.SetValue(std::move(aOther.mValue.mUTF8String.Value()));
      break;
    }
  }
}



bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToTimelineRangeOffset(BindingCallContext& cx, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  tryNext = false;
  { // scope for memberSlot
    TimelineRangeOffset& memberSlot = RawSetAsTimelineRangeOffset();
    if (!IsConvertibleToDictionary(value)) {
      DestroyTimelineRangeOffset();
      tryNext = true;
      return true;
    }
    if (!memberSlot.Init(cx, value, "TimelineRangeOffset branch of (TimelineRangeOffset or CSSNumericValue or CSSKeywordValue or USVString)", passedToJSImpl)) {
      return false;
    }
  }
  return true;
}

bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToTimelineRangeOffset(JSContext* cx_, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  BindingCallContext cx(cx_, nullptr);
  return TrySetToTimelineRangeOffset(cx, value, tryNext, passedToJSImpl);
}

[[nodiscard]] TimelineRangeOffset&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::RawSetAsTimelineRangeOffset()
{
  if (mType == eTimelineRangeOffset) {
    return mValue.mTimelineRangeOffset.Value();
  }
  MOZ_ASSERT(mType == eUninitialized);
  mType = eTimelineRangeOffset;
  return mValue.mTimelineRangeOffset.SetValue();
}

[[nodiscard]] TimelineRangeOffset&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::SetAsTimelineRangeOffset()
{
  if (mType == eTimelineRangeOffset) {
    return mValue.mTimelineRangeOffset.Value();
  }
  Uninit();
  mType = eTimelineRangeOffset;
  return mValue.mTimelineRangeOffset.SetValue();
}


void
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::DestroyTimelineRangeOffset()
{
  MOZ_RELEASE_ASSERT(IsTimelineRangeOffset(), "Wrong type!");
  mValue.mTimelineRangeOffset.Destroy();
  mType = eUninitialized;
}



bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToCSSNumericValue(BindingCallContext& cx, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  tryNext = false;
  { // scope for memberSlot
    OwningNonNull<mozilla::dom::CSSNumericValue>& memberSlot = RawSetAsCSSNumericValue();
    static_assert(IsRefcounted<mozilla::dom::CSSNumericValue>::value, "We can only store refcounted classes.");
    {
      // Our JSContext should be in the right global to do unwrapping in.
      nsresult rv = UnwrapObject<prototypes::id::CSSNumericValue, mozilla::dom::CSSNumericValue>(value, memberSlot, cx);
      if (NS_FAILED(rv)) {
        DestroyCSSNumericValue();
        tryNext = true;
        return true;
      }
    }
  }
  return true;
}

bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToCSSNumericValue(JSContext* cx_, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  BindingCallContext cx(cx_, nullptr);
  return TrySetToCSSNumericValue(cx, value, tryNext, passedToJSImpl);
}

[[nodiscard]] OwningNonNull<mozilla::dom::CSSNumericValue>&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::RawSetAsCSSNumericValue()
{
  if (mType == eCSSNumericValue) {
    return mValue.mCSSNumericValue.Value();
  }
  MOZ_ASSERT(mType == eUninitialized);
  mType = eCSSNumericValue;
  return mValue.mCSSNumericValue.SetValue();
}

[[nodiscard]] OwningNonNull<mozilla::dom::CSSNumericValue>&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::SetAsCSSNumericValue()
{
  if (mType == eCSSNumericValue) {
    return mValue.mCSSNumericValue.Value();
  }
  Uninit();
  mType = eCSSNumericValue;
  return mValue.mCSSNumericValue.SetValue();
}


void
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::DestroyCSSNumericValue()
{
  MOZ_RELEASE_ASSERT(IsCSSNumericValue(), "Wrong type!");
  mValue.mCSSNumericValue.Destroy();
  mType = eUninitialized;
}



bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToCSSKeywordValue(BindingCallContext& cx, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  tryNext = false;
  { // scope for memberSlot
    OwningNonNull<mozilla::dom::CSSKeywordValue>& memberSlot = RawSetAsCSSKeywordValue();
    static_assert(IsRefcounted<mozilla::dom::CSSKeywordValue>::value, "We can only store refcounted classes.");
    {
      // Our JSContext should be in the right global to do unwrapping in.
      nsresult rv = UnwrapObject<prototypes::id::CSSKeywordValue, mozilla::dom::CSSKeywordValue>(value, memberSlot, cx);
      if (NS_FAILED(rv)) {
        DestroyCSSKeywordValue();
        tryNext = true;
        return true;
      }
    }
  }
  return true;
}

bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToCSSKeywordValue(JSContext* cx_, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  BindingCallContext cx(cx_, nullptr);
  return TrySetToCSSKeywordValue(cx, value, tryNext, passedToJSImpl);
}

[[nodiscard]] OwningNonNull<mozilla::dom::CSSKeywordValue>&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::RawSetAsCSSKeywordValue()
{
  if (mType == eCSSKeywordValue) {
    return mValue.mCSSKeywordValue.Value();
  }
  MOZ_ASSERT(mType == eUninitialized);
  mType = eCSSKeywordValue;
  return mValue.mCSSKeywordValue.SetValue();
}

[[nodiscard]] OwningNonNull<mozilla::dom::CSSKeywordValue>&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::SetAsCSSKeywordValue()
{
  if (mType == eCSSKeywordValue) {
    return mValue.mCSSKeywordValue.Value();
  }
  Uninit();
  mType = eCSSKeywordValue;
  return mValue.mCSSKeywordValue.SetValue();
}


void
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::DestroyCSSKeywordValue()
{
  MOZ_RELEASE_ASSERT(IsCSSKeywordValue(), "Wrong type!");
  mValue.mCSSKeywordValue.Destroy();
  mType = eUninitialized;
}



bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::TrySetToUTF8String(JSContext* cx, JS::Handle<JS::Value> value, bool& tryNext, bool passedToJSImpl)
{
  tryNext = false;
  { // scope for memberSlot
    nsCString& memberSlot = RawSetAsUTF8String();
    if (!ConvertJSValueToString(cx, value, eStringify, eStringify, memberSlot)) {
      return false;
    }
  }
  return true;
}

[[nodiscard]] nsCString&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::RawSetAsUTF8String()
{
  if (mType == eUTF8String) {
    return mValue.mUTF8String.Value();
  }
  MOZ_ASSERT(mType == eUninitialized);
  mType = eUTF8String;
  return mValue.mUTF8String.SetValue();
}

[[nodiscard]] nsCString&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::SetAsUTF8String()
{
  if (mType == eUTF8String) {
    return mValue.mUTF8String.Value();
  }
  Uninit();
  mType = eUTF8String;
  return mValue.mUTF8String.SetValue();
}



void
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::DestroyUTF8String()
{
  MOZ_RELEASE_ASSERT(IsUTF8String(), "Wrong type!");
  mValue.mUTF8String.Destroy();
  mType = eUninitialized;
}



bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::Init(BindingCallContext& cx, JS::Handle<JS::Value> value, const char* sourceDescription, bool passedToJSImpl)
{
  MOZ_ASSERT(mType == eUninitialized);

  bool done = false, failed = false, tryNext;
  if (value.isObject()) {
    done = (failed = !TrySetToCSSNumericValue(cx, value, tryNext, passedToJSImpl)) || !tryNext ||
           (failed = !TrySetToCSSKeywordValue(cx, value, tryNext, passedToJSImpl)) || !tryNext;
  }
  if (!done) {
    done = (failed = !TrySetToTimelineRangeOffset(cx, value, tryNext, passedToJSImpl)) || !tryNext;
  }
  if (!done) {
    do {
      done = (failed = !TrySetToUTF8String(cx, value, tryNext)) || !tryNext;
      break;
    } while (false);
  }
  if (failed) {
    return false;
  }
  if (!done) {
    cx.ThrowErrorMessage<MSG_NOT_IN_UNION>(sourceDescription, "CSSNumericValue, CSSKeywordValue, TimelineRangeOffset");
    return false;
  }
  return true;
}

bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::Init(JSContext* cx_, JS::Handle<JS::Value> value, const char* sourceDescription, bool passedToJSImpl)
{
  BindingCallContext cx(cx_, nullptr);
  return Init(cx, value, sourceDescription, passedToJSImpl);
}

void
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::Uninit()
{
  switch (mType) {
    case eUninitialized: {
      break;
    }
    case eTimelineRangeOffset: {
      DestroyTimelineRangeOffset();
      break;
    }
    case eCSSNumericValue: {
      DestroyCSSNumericValue();
      break;
    }
    case eCSSKeywordValue: {
      DestroyCSSKeywordValue();
      break;
    }
    case eUTF8String: {
      DestroyUTF8String();
      break;
    }
  }
}

bool
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj, JS::MutableHandle<JS::Value> rval) const
{
  switch (mType) {
    case eUninitialized: {
      return false;
    }
    case eTimelineRangeOffset: {
      if (!mValue.mTimelineRangeOffset.Value().ToObjectInternal(cx, rval)) {
        return false;
      }
      return true;
    }
    case eCSSNumericValue: {
      if (!GetOrCreateDOMReflector(cx, mValue.mCSSNumericValue.Value(), rval)) {
        MOZ_ASSERT(JS_IsExceptionPending(cx));
        return false;
      }
      return true;
    }
    case eCSSKeywordValue: {
      if (!GetOrCreateDOMReflector(cx, mValue.mCSSKeywordValue.Value(), rval)) {
        MOZ_ASSERT(JS_IsExceptionPending(cx));
        return false;
      }
      return true;
    }
    case eUTF8String: {
      if (!NonVoidUTF8StringToJsval(cx, mValue.mUTF8String.Value(), rval)) {
        return false;
      }
      return true;
    }
    default: {
      return false;
    }
  }
}

OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::operator=(OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String&& aOther)
{
  this->~OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String();
  new (this) OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String (std::move(aOther));
  return *this;
}


OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String&
OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String::operator=(const OwningTimelineRangeOffsetOrCSSNumericValueOrCSSKeywordValueOrUTF8String& aOther)
{
  switch (aOther.mType) {
    case eUninitialized: {
      MOZ_ASSERT(mType == eUninitialized,
                 "We need to destroy ourselves?");
      break;
    }
    case eTimelineRangeOffset: {
      SetAsTimelineRangeOffset() = aOther.GetAsTimelineRangeOffset();
      break;
    }
    case eCSSNumericValue: {
      SetAsCSSNumericValue() = aOther.GetAsCSSNumericValue();
      break;
    }
    case eCSSKeywordValue: {
      SetAsCSSKeywordValue() = aOther.GetAsCSSKeywordValue();
      break;
    }
    case eUTF8String: {
      SetAsUTF8String() = aOther.GetAsUTF8String();
      break;
    }
  }
  return *this;
}



KeyframeAnimationOptions::KeyframeAnimationOptions()
  : KeyframeEffectOptions(FastDictionaryInitializer())
{
  // Safe to pass a null context if we pass a null value
  Init(nullptr, JS::NullHandleValue);
}




bool
KeyframeAnimationOptions::InitIds(JSContext* cx, KeyframeAnimationOptionsAtoms* atomsCache)
{
  MOZ_ASSERT(reinterpret_cast<jsid*>(atomsCache)->isVoid());

  // Initialize these in reverse order so that any failure leaves the first one
  // uninitialized.
  if (!atomsCache->timeline_id.init(cx, "timeline") ||
      !atomsCache->rangeStart_id.init(cx, "rangeStart") ||
      !atomsCache->rangeEnd_id.init(cx, "rangeEnd") ||
      !atomsCache->id_id.init(cx, "id")) {
    return false;
  }
  return true;
}

bool
KeyframeAnimationOptions::Init(BindingCallContext& cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
{
  // Passing a null JSContext is OK only if we're initing from null,
  // Since in that case we will not have to do any property gets
  // Also evaluate isNullOrUndefined in order to avoid false-positive
  // checkers by static analysis tools
  MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
  KeyframeAnimationOptionsAtoms* atomsCache = nullptr;
  if (cx) {
    atomsCache = GetAtomCache<KeyframeAnimationOptionsAtoms>(cx);
    if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
        !InitIds(cx, atomsCache)) {
      return false;
    }
  }

  // Per spec, we init the parent's members first
  if (!KeyframeEffectOptions::Init(cx, val)) {
    return false;
  }

  bool isNull = val.isNullOrUndefined();
  // We only need these if !isNull, in which case we have |cx|.
  Maybe<JS::Rooted<JSObject *> > object;
  Maybe<JS::Rooted<JS::Value> > temp;
  if (!isNull) {
    MOZ_ASSERT(cx);
    object.emplace(cx, &val.toObject());
    temp.emplace(cx);
  }
  if (!isNull) {
    if (!JS_GetPropertyById(cx, *object, atomsCache->id_id, temp.ptr())) {
      return false;
    }
  }
  if (!isNull && !temp->isUndefined()) {
    if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, mId)) {
      return false;
    }
  } else {
    mId.AssignLiteral(u"");
  }
  mIsAnyMemberPresent = true;

  if (!isNull) {
    if (StaticPrefs::layout_css_scroll_driven_animations_enabled()) {
      if (!JS_GetPropertyById(cx, *object, atomsCache->rangeEnd_id, temp.ptr())) {
        return false;
      }
    } else {
      temp->setUndefined();
    }
  }
  mRangeEnd.Uninit();
  if (!(!isNull && !temp->isUndefined())) {
    mRangeEnd.SetStringLiteral("normal");
  } else {
    if (!mRangeEnd.Init(cx, temp.ref(), "'rangeEnd' member of KeyframeAnimationOptions", passedToJSImpl)) {
      return false;
    }
  }
  mIsAnyMemberPresent = true;

  if (!isNull) {
    if (StaticPrefs::layout_css_scroll_driven_animations_enabled()) {
      if (!JS_GetPropertyById(cx, *object, atomsCache->rangeStart_id, temp.ptr())) {
        return false;
      }
    } else {
      temp->setUndefined();
    }
  }
  mRangeStart.Uninit();
  if (!(!isNull && !temp->isUndefined())) {
    mRangeStart.SetStringLiteral("normal");
  } else {
    if (!mRangeStart.Init(cx, temp.ref(), "'rangeStart' member of KeyframeAnimationOptions", passedToJSImpl)) {
      return false;
    }
  }
  mIsAnyMemberPresent = true;

  if (!isNull) {
    if (StaticPrefs::layout_css_scroll_driven_animations_enabled()) {
      if (!JS_GetPropertyById(cx, *object, atomsCache->timeline_id, temp.ptr())) {
        return false;
      }
    } else {
      temp->setUndefined();
    }
  }
  if (!isNull && !temp->isUndefined()) {
    mTimeline.Construct();
    if (temp.ref().isObject()) {
      static_assert(IsRefcounted<mozilla::dom::AnimationTimeline>::value, "We can only store refcounted classes.");
      {
        // Our JSContext should be in the right global to do unwrapping in.
        nsresult rv = UnwrapObject<prototypes::id::AnimationTimeline, mozilla::dom::AnimationTimeline>(temp.ptr(), (mTimeline.Value()), cx);
        if (NS_FAILED(rv)) {
          cx.ThrowErrorMessage<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("'timeline' member of KeyframeAnimationOptions", "AnimationTimeline");
          return false;
        }
      }
    } else if (temp.ref().isNullOrUndefined()) {
      (mTimeline.Value()) = nullptr;
    } else {
      cx.ThrowErrorMessage<MSG_NOT_OBJECT>("'timeline' member of KeyframeAnimationOptions");
      return false;
    }
    mIsAnyMemberPresent = true;
  }
  return true;
}

bool
KeyframeAnimationOptions::Init(JSContext* cx_, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
{
  // We don't want to use sourceDescription for our context here;
  // that's not really what it's formatted for.
  BindingCallContext cx(cx_, nullptr);
  return Init(cx, val, sourceDescription, passedToJSImpl);
}

void
KeyframeAnimationOptions::TraceDictionary(JSTracer* trc)
{
  KeyframeEffectOptions::TraceDictionary(trc);
}



KeyframeAnimationOptions&
KeyframeAnimationOptions::operator=(const KeyframeAnimationOptions& aOther)
{
  KeyframeEffectOptions::operator=(aOther);
  mId = aOther.mId;
  mRangeEnd = aOther.mRangeEnd;
  mRangeStart = aOther.mRangeStart;
  mTimeline.Reset();
  if (aOther.mTimeline.WasPassed()) {
    mTimeline.Construct(aOther.mTimeline.Value());
  }
  return *this;
}


} // namespace mozilla::dom
