/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "third_party/blink/renderer/core/animation/effect_input.h"

#include "third_party/blink/renderer/bindings/core/v8/array_value.h"
#include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_string_sequence.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_base_keyframe.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_base_property_indexed_keyframe.h"
#include "third_party/blink/renderer/core/animation/animation_input_helpers.h"
#include "third_party/blink/renderer/core/animation/compositor_animations.h"
#include "third_party/blink/renderer/core/animation/css/css_animations.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
#include "third_party/blink/renderer/core/animation/string_keyframe.h"
#include "third_party/blink/renderer/core/css/css_style_sheet.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/frame_console.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/ascii_ctype.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "v8/include/v8.h"

namespace blink {

namespace {

// Converts the composite property of a BasePropertyIndexedKeyframe into a
// vector of base::Optional<EffectModel::CompositeOperation> enums.
Vector<base::Optional<EffectModel::CompositeOperation>> ParseCompositeProperty(
    const BasePropertyIndexedKeyframe* keyframe) {
  const CompositeOperationOrAutoOrCompositeOperationOrAutoSequence& composite =
      keyframe->composite();

  if (composite.IsCompositeOperationOrAuto()) {
    return {EffectModel::StringToCompositeOperation(
        composite.GetAsCompositeOperationOrAuto())};
  }

  Vector<base::Optional<EffectModel::CompositeOperation>> result;
  for (const String& composite_operation_string :
       composite.GetAsCompositeOperationOrAutoSequence()) {
    result.push_back(
        EffectModel::StringToCompositeOperation(composite_operation_string));
  }
  return result;
}

void SetKeyframeValue(Element* element,
                      Document& document,
                      StringKeyframe& keyframe,
                      const String& property,
                      const String& value,
                      ExecutionContext* execution_context) {
  StyleSheetContents* style_sheet_contents = document.ElementSheet().Contents();
  CSSPropertyID css_property =
      AnimationInputHelpers::KeyframeAttributeToCSSProperty(property, document);
  SecureContextMode secure_context_mode =
      document.GetExecutionContext()
          ? document.GetExecutionContext()->GetSecureContextMode()
          : SecureContextMode::kInsecureContext;
  if (css_property != CSSPropertyID::kInvalid) {
    MutableCSSPropertyValueSet::SetResult set_result =
        css_property == CSSPropertyID::kVariable
            ? keyframe.SetCSSPropertyValue(AtomicString(property), value,
                                           secure_context_mode,
                                           style_sheet_contents)
            : keyframe.SetCSSPropertyValue(css_property, value,
                                           secure_context_mode,
                                           style_sheet_contents);
    if (!set_result.did_parse && execution_context) {
      if (document.GetFrame()) {
        document.GetFrame()->Console().AddMessage(
            MakeGarbageCollected<ConsoleMessage>(
                mojom::ConsoleMessageSource::kJavaScript,
                mojom::ConsoleMessageLevel::kWarning,
                "Invalid keyframe value for property " + property + ": " +
                    value));
      }
    }
    return;
  }
  css_property =
      AnimationInputHelpers::KeyframeAttributeToPresentationAttribute(property,
                                                                      element);
  if (css_property != CSSPropertyID::kInvalid) {
    keyframe.SetPresentationAttributeValue(CSSProperty::Get(css_property),
                                           value, secure_context_mode,
                                           style_sheet_contents);
    return;
  }
  const QualifiedName* svg_attribute =
      AnimationInputHelpers::KeyframeAttributeToSVGAttribute(property, element);
  if (svg_attribute)
    keyframe.SetSVGAttributeValue(*svg_attribute, value);
}

bool ValidatePartialKeyframes(const StringKeyframeVector& keyframes) {
  // WebAnimationsAPIEnabled guards both additive animations and allowing
  // partial (implicit) keyframes.
  if (RuntimeEnabledFeatures::WebAnimationsAPIEnabled())
    return true;

  // An implicit keyframe is inserted in the below cases. Note that the 'first'
  // keyframe is actually all keyframes with offset 0.0, and the 'last' keyframe
  // is actually all keyframes with offset 1.0.
  //
  //   1. A given property is present somewhere in the full set of keyframes,
  //      but is either not present in the first keyframe (requiring an implicit
  //      start value for that property) or last keyframe (requiring an implicit
  //      end value for that property).
  //
  //   2. There is no first keyframe (requiring an implicit start keyframe), or
  //      no last keyframe (requiring an implicit end keyframe).
  //
  // We only care about CSS properties here; animating SVG elements is protected
  // by a different runtime flag.

  Vector<double> computed_offsets =
      KeyframeEffectModelBase::GetComputedOffsets(keyframes);

  PropertyHandleSet properties_with_offset_0;
  PropertyHandleSet properties_with_offset_1;
  for (wtf_size_t i = 0; i < keyframes.size(); i++) {
    for (const PropertyHandle& property : keyframes[i]->Properties()) {
      if (!property.IsCSSProperty())
        continue;

      if (computed_offsets[i] == 0.0) {
        properties_with_offset_0.insert(property);
      } else {
        if (!properties_with_offset_0.Contains(property))
          return false;
        if (computed_offsets[i] == 1.0) {
          properties_with_offset_1.insert(property);
        }
      }
    }
  }

  // At this point we have compared all keyframes with offset > 0 against the
  // properties contained in the first keyframe, and found that they match. Now
  // we just need to make sure that there aren't any properties in the first
  // keyframe that aren't in the last keyframe.
  return properties_with_offset_0.size() == properties_with_offset_1.size();
}

// Ensures that a CompositeOperation is of an allowed value for a given
// StringKeyframe and the current runtime flags.
EffectModel::CompositeOperation ResolveCompositeOperationForKeyframe(
    EffectModel::CompositeOperation composite,
    StringKeyframe* keyframe) {
  bool additive_composite = composite == EffectModel::kCompositeAdd ||
                            composite == EffectModel::kCompositeAccumulate;
  if (!RuntimeEnabledFeatures::WebAnimationsAPIEnabled() &&
      keyframe->HasCssProperty() && additive_composite) {
    return EffectModel::kCompositeReplace;
  }
  return composite;
}

bool IsAnimatableKeyframeAttribute(const String& property,
                                   Element* element,
                                   const Document& document) {
  CSSPropertyID css_property =
      AnimationInputHelpers::KeyframeAttributeToCSSProperty(property, document);
  if (css_property != CSSPropertyID::kInvalid) {
    return !CSSAnimations::IsAnimationAffectingProperty(
        CSSProperty::Get(css_property));
  }

  css_property =
      AnimationInputHelpers::KeyframeAttributeToPresentationAttribute(property,
                                                                      element);
  if (css_property != CSSPropertyID::kInvalid)
    return true;

  return !!AnimationInputHelpers::KeyframeAttributeToSVGAttribute(property,
                                                                  element);
}

void AddPropertyValuePairsForKeyframe(
    v8::Isolate* isolate,
    v8::Local<v8::Object> keyframe_obj,
    Element* element,
    const Document& document,
    Vector<std::pair<String, String>>& property_value_pairs,
    ExceptionState& exception_state) {
  Vector<String> keyframe_properties =
      GetOwnPropertyNames(isolate, keyframe_obj, exception_state);
  if (exception_state.HadException())
    return;

  // By spec, we must sort the properties in "ascending order by the Unicode
  // codepoints that define each property name."
  std::sort(keyframe_properties.begin(), keyframe_properties.end(),
            WTF::CodeUnitCompareLessThan);

  v8::TryCatch try_catch(isolate);
  for (const auto& property : keyframe_properties) {
    if (property == "offset" || property == "float" ||
        property == "composite" || property == "easing") {
      continue;
    }

    // By spec, we are not allowed to access any non-animatable property.
    if (!IsAnimatableKeyframeAttribute(property, element, document))
      continue;

    // By spec, we are only allowed to access a given (property, value) pair
    // once. This is observable by the web client, so we take care to adhere
    // to that.
    v8::Local<v8::Value> v8_value;
    if (!keyframe_obj
             ->Get(isolate->GetCurrentContext(), V8String(isolate, property))
             .ToLocal(&v8_value)) {
      exception_state.RethrowV8Exception(try_catch.Exception());
      return;
    }

    if (v8_value->IsArray()) {
      // Since allow-lists is false, array values should be ignored.
      continue;
    }

    String string_value = NativeValueTraits<IDLString>::NativeValue(
        isolate, v8_value, exception_state);
    if (exception_state.HadException())
      return;
    property_value_pairs.push_back(std::make_pair(property, string_value));
  }
}

StringKeyframeVector ConvertArrayForm(Element* element,
                                      Document& document,
                                      ScriptIterator iterator,
                                      ScriptState* script_state,
                                      ExceptionState& exception_state) {
  v8::Isolate* isolate = script_state->GetIsolate();

  // This loop captures step 5 of the procedure to process a keyframes argument,
  // in the case where the argument is iterable.
  HeapVector<Member<const BaseKeyframe>> processed_base_keyframes;
  Vector<Vector<std::pair<String, String>>> processed_properties;
  ExecutionContext* execution_context = ExecutionContext::From(script_state);
  while (iterator.Next(execution_context, exception_state)) {
    if (exception_state.HadException())
      return {};

    // The value should already be non-empty, as guaranteed by the call to Next
    // and the exception_state check above.
    v8::Local<v8::Value> keyframe = iterator.GetValue().ToLocalChecked();

    if (!keyframe->IsObject() && !keyframe->IsNullOrUndefined()) {
      exception_state.ThrowTypeError(
          "Keyframes must be objects, or null or undefined");
      return {};
    }

    BaseKeyframe* base_keyframe = NativeValueTraits<BaseKeyframe>::NativeValue(
        isolate, keyframe, exception_state);
    Vector<std::pair<String, String>> property_value_pairs;
    if (exception_state.HadException())
      return {};

    if (!keyframe->IsNullOrUndefined()) {
      AddPropertyValuePairsForKeyframe(
          isolate, v8::Local<v8::Object>::Cast(keyframe), element, document,
          property_value_pairs, exception_state);
      if (exception_state.HadException())
        return {};
    }

    processed_base_keyframes.push_back(base_keyframe);
    processed_properties.push_back(property_value_pairs);
  }
  // If the very first call to next() throws the above loop will never be
  // entered, so we have to catch that here.
  if (exception_state.HadException())
    return {};

  // 6. If processed keyframes is not loosely sorted by offset, throw a
  // TypeError and abort these steps.
  double previous_offset = -std::numeric_limits<double>::infinity();
  const wtf_size_t num_processed_keyframes = processed_base_keyframes.size();
  for (wtf_size_t i = 0; i < num_processed_keyframes; ++i) {
    if (!processed_base_keyframes[i]->hasOffsetNonNull())
      continue;

    double offset = processed_base_keyframes[i]->offsetNonNull();
    if (offset < previous_offset) {
      exception_state.ThrowTypeError(
          "Offsets must be montonically non-decreasing.");
      return {};
    }
    previous_offset = offset;
  }

  // 7. If there exist any keyframe in processed keyframes whose keyframe
  // offset is non-null and less than zero or greater than one, throw a
  // TypeError and abort these steps.
  for (wtf_size_t i = 0; i < num_processed_keyframes; ++i) {
    if (!processed_base_keyframes[i]->hasOffsetNonNull())
      continue;

    double offset = processed_base_keyframes[i]->offsetNonNull();
    if (offset < 0 || offset > 1) {
      exception_state.ThrowTypeError(
          "Offsets must be null or in the range [0,1].");
      return {};
    }
  }

  StringKeyframeVector keyframes;
  for (wtf_size_t i = 0; i < num_processed_keyframes; ++i) {
    // Now we create the actual Keyframe object. We start by assigning the
    // offset and composite values; conceptually these were actually added in
    // step 5 above but we didn't have a keyframe object then.
    const BaseKeyframe* base_keyframe = processed_base_keyframes[i];
    auto* keyframe = MakeGarbageCollected<StringKeyframe>();
    if (base_keyframe->hasOffset()) {
      keyframe->SetOffset(base_keyframe->offset());
    }

    // 8.1. For each property-value pair in frame, parse the property value
    // using the syntax specified for that property.
    for (const auto& pair : processed_properties[i]) {
      // TODO(crbug.com/777971): Make parsing of property values spec-compliant.
      SetKeyframeValue(element, document, *keyframe, pair.first, pair.second,
                       execution_context);
    }

    base::Optional<EffectModel::CompositeOperation> composite =
        EffectModel::StringToCompositeOperation(base_keyframe->composite());
    if (composite) {
      keyframe->SetComposite(
          ResolveCompositeOperationForKeyframe(composite.value(), keyframe));
    }

    // 8.2. Let the timing function of frame be the result of parsing the
    // “easing” property on frame using the CSS syntax defined for the easing
    // property of the AnimationEffectTimingReadOnly interface.
    //
    // If parsing the “easing” property fails, throw a TypeError and abort this
    // procedure.
    scoped_refptr<TimingFunction> timing_function =
        AnimationInputHelpers::ParseTimingFunction(base_keyframe->easing(),
                                                   &document, exception_state);
    if (!timing_function)
      return {};
    keyframe->SetEasing(timing_function);

    keyframes.push_back(keyframe);
  }

  DCHECK(!exception_state.HadException());
  return keyframes;
}

// Extracts the values for a given property in the input keyframes. As per the
// spec property values for the object-notation form have type (DOMString or
// sequence<DOMString>).
bool GetPropertyIndexedKeyframeValues(const v8::Local<v8::Object>& keyframe,
                                      const String& property,
                                      ScriptState* script_state,
                                      ExceptionState& exception_state,
                                      Vector<String>& result) {
  DCHECK(result.IsEmpty());

  // By spec, we are only allowed to access a given (property, value) pair once.
  // This is observable by the web client, so we take care to adhere to that.
  v8::Local<v8::Value> v8_value;
  v8::TryCatch try_catch(script_state->GetIsolate());
  v8::Local<v8::Context> context = script_state->GetContext();
  v8::Isolate* isolate = script_state->GetIsolate();
  if (!keyframe->Get(context, V8String(isolate, property)).ToLocal(&v8_value)) {
    exception_state.RethrowV8Exception(try_catch.Exception());
    return {};
  }

  StringOrStringSequence string_or_string_sequence;
  V8StringOrStringSequence::ToImpl(
      script_state->GetIsolate(), v8_value, string_or_string_sequence,
      UnionTypeConversionMode::kNotNullable, exception_state);
  if (exception_state.HadException())
    return false;

  if (string_or_string_sequence.IsString())
    result.push_back(string_or_string_sequence.GetAsString());
  else
    result = string_or_string_sequence.GetAsStringSequence();

  return true;
}

// Implements the procedure to "process a keyframes argument" from the
// web-animations spec for an object form keyframes argument.
//
// See https://drafts.csswg.org/web-animations/#processing-a-keyframes-argument
StringKeyframeVector ConvertObjectForm(Element* element,
                                       Document& document,
                                       const v8::Local<v8::Object>& v8_keyframe,
                                       ScriptState* script_state,
                                       ExceptionState& exception_state) {
  // We implement much of this procedure out of order from the way the spec is
  // written, to avoid repeatedly going over the list of keyframes.
  // The web-observable behavior should be the same as the spec.

  // Extract the offset, easing, and composite as per step 1 of the 'procedure
  // to process a keyframe-like object'.
  BasePropertyIndexedKeyframe* property_indexed_keyframe =
      NativeValueTraits<BasePropertyIndexedKeyframe>::NativeValue(
          script_state->GetIsolate(), v8_keyframe, exception_state);
  if (exception_state.HadException())
    return {};

  Vector<base::Optional<double>> offsets;
  if (property_indexed_keyframe->offset().IsNull())
    offsets.push_back(base::nullopt);
  else if (property_indexed_keyframe->offset().IsDouble())
    offsets.push_back(property_indexed_keyframe->offset().GetAsDouble());
  else
    offsets = property_indexed_keyframe->offset().GetAsDoubleOrNullSequence();

  // The web-animations spec explicitly states that easings should be kept as
  // DOMStrings here and not parsed into timing functions until later.
  Vector<String> easings;
  if (property_indexed_keyframe->easing().IsString())
    easings.push_back(property_indexed_keyframe->easing().GetAsString());
  else
    easings = property_indexed_keyframe->easing().GetAsStringSequence();

  Vector<base::Optional<EffectModel::CompositeOperation>> composite_operations =
      ParseCompositeProperty(property_indexed_keyframe);

  // Next extract all animatable properties from the input argument and iterate
  // through them, processing each as a list of values for that property. This
  // implements both steps 2-7 of the 'procedure to process a keyframe-like
  // object' and step 5.2 of the 'procedure to process a keyframes argument'.

  Vector<String> keyframe_properties = GetOwnPropertyNames(
      script_state->GetIsolate(), v8_keyframe, exception_state);
  if (exception_state.HadException())
    return {};

  // Steps 5.2 - 5.4 state that the user agent is to:
  //
  //   * Create sets of 'property keyframes' with no offset.
  //   * Calculate computed offsets for each set of keyframes individually.
  //   * Join the sets together and merge those with identical computed offsets.
  //
  // This is equivalent to just keeping a hashmap from computed offset to a
  // single keyframe, which simplifies the parsing logic.
  HeapHashMap<double, Member<StringKeyframe>> keyframes;

  // By spec, we must sort the properties in "ascending order by the Unicode
  // codepoints that define each property name."
  std::sort(keyframe_properties.begin(), keyframe_properties.end(),
            WTF::CodeUnitCompareLessThan);

  for (const auto& property : keyframe_properties) {
    if (property == "offset" || property == "float" ||
        property == "composite" || property == "easing") {
      continue;
    }

    // By spec, we are not allowed to access any non-animatable property.
    if (!IsAnimatableKeyframeAttribute(property, element, document))
      continue;

    Vector<String> values;
    if (!GetPropertyIndexedKeyframeValues(v8_keyframe, property, script_state,
                                          exception_state, values)) {
      return {};
    }

    // Now create a keyframe (or retrieve and augment an existing one) for each
    // value this property maps to. As explained above, this loop performs both
    // the initial creation and merging mentioned in the spec.
    wtf_size_t num_keyframes = values.size();
    ExecutionContext* execution_context = ExecutionContext::From(script_state);
    for (wtf_size_t i = 0; i < num_keyframes; ++i) {
      // As all offsets are null for these 'property keyframes', the computed
      // offset is just the fractional position of each keyframe in the array.
      //
      // The only special case is that when there is only one keyframe the sole
      // computed offset is defined as 1.
      double computed_offset =
          (num_keyframes == 1) ? 1 : i / double(num_keyframes - 1);

      auto result = keyframes.insert(computed_offset, nullptr);
      if (result.is_new_entry)
        result.stored_value->value = MakeGarbageCollected<StringKeyframe>();

      SetKeyframeValue(element, document, *result.stored_value->value, property,
                       values[i], execution_context);
    }
  }

  // 5.3 Sort processed keyframes by the computed keyframe offset of each
  // keyframe in increasing order.
  Vector<double> keys;
  for (const auto& key : keyframes.Keys())
    keys.push_back(key);
  std::sort(keys.begin(), keys.end());

  // Steps 5.5 - 5.12 deal with assigning the user-specified offset, easing, and
  // composite properties to the keyframes.
  //
  // This loop also implements steps 6, 7, and 8 of the spec. Because nothing is
  // user-observable at this point, we can operate out of order. Note that this
  // may result in us throwing a different order of TypeErrors than other user
  // agents[1], but as all exceptions are TypeErrors this is not observable by
  // the web client.
  //
  // [1] E.g. if the offsets are [2, 0] we will throw due to the first offset
  //     being > 1 before we throw due to the offsets not being loosely ordered.
  StringKeyframeVector results;
  double previous_offset = 0.0;
  for (wtf_size_t i = 0; i < keys.size(); i++) {
    auto* keyframe = keyframes.at(keys[i]);

    if (i < offsets.size()) {
      base::Optional<double> offset = offsets[i];
      // 6. If processed keyframes is not loosely sorted by offset, throw a
      // TypeError and abort these steps.
      if (offset.has_value()) {
        if (offset.value() < previous_offset) {
          exception_state.ThrowTypeError(
              "Offsets must be montonically non-decreasing.");
          return {};
        }
        previous_offset = offset.value();
      }

      // 7. If there exist any keyframe in processed keyframes whose keyframe
      // offset is non-null and less than zero or greater than one, throw a
      // TypeError and abort these steps.
      if (offset.has_value() && (offset.value() < 0 || offset.value() > 1)) {
        exception_state.ThrowTypeError(
            "Offsets must be null or in the range [0,1].");
        return {};
      }

      keyframe->SetOffset(offset);
    }

    // At this point in the code we have read all the properties we will read
    // from the input object, so it is safe to parse the easing strings. See the
    // note on step 8.2.
    if (!easings.IsEmpty()) {
      // 5.9 If easings has fewer items than property keyframes, repeat the
      // elements in easings successively starting from the beginning of the
      // list until easings has as many items as property keyframes.
      const String& easing = easings[i % easings.size()];

      // 8.2 Let the timing function of frame be the result of parsing the
      // "easing" property on frame using the CSS syntax defined for the easing
      // property of the AnimationEffectTimingReadOnly interface.
      //
      // If parsing the “easing” property fails, throw a TypeError and abort
      // this procedure.
      scoped_refptr<TimingFunction> timing_function =
          AnimationInputHelpers::ParseTimingFunction(easing, &document,
                                                     exception_state);
      if (!timing_function)
        return {};

      keyframe->SetEasing(timing_function);
    }

    if (!composite_operations.IsEmpty()) {
      // 5.12.2 As with easings, if composite modes has fewer items than
      // property keyframes, repeat the elements in composite modes successively
      // starting from the beginning of the list until composite modes has as
      // many items as property keyframes.
      base::Optional<EffectModel::CompositeOperation> composite =
          composite_operations[i % composite_operations.size()];
      if (composite) {
        keyframe->SetComposite(
            ResolveCompositeOperationForKeyframe(composite.value(), keyframe));
      }
    }

    results.push_back(keyframe);
  }

  // Step 8 of the spec is done above (or will be): parsing property values
  // according to syntax for the property (discarding with console warning on
  // fail) and parsing each easing property.
  // TODO(crbug.com/777971): Fix parsing of property values to adhere to spec.

  // 9. Parse each of the values in unused easings using the CSS syntax defined
  // for easing property of the AnimationEffectTimingReadOnly interface, and if
  // any of the values fail to parse, throw a TypeError and abort this
  // procedure.
  for (wtf_size_t i = results.size(); i < easings.size(); i++) {
    scoped_refptr<TimingFunction> timing_function =
        AnimationInputHelpers::ParseTimingFunction(easings[i], &document,
                                                   exception_state);
    if (!timing_function)
      return {};
  }

  DCHECK(!exception_state.HadException());
  return results;
}

bool HasAdditiveCompositeCSSKeyframe(
    const KeyframeEffectModelBase::KeyframeGroupMap& keyframe_groups) {
  for (const auto& keyframe_group : keyframe_groups) {
    PropertyHandle property = keyframe_group.key;
    if (!property.IsCSSProperty())
      continue;
    for (const auto& keyframe : keyframe_group.value->Keyframes()) {
      if (keyframe->Composite() == EffectModel::kCompositeAdd ||
          keyframe->Composite() == EffectModel::kCompositeAccumulate) {
        return true;
      }
    }
  }
  return false;
}
}  // namespace

KeyframeEffectModelBase* EffectInput::Convert(
    Element* element,
    const ScriptValue& keyframes,
    EffectModel::CompositeOperation composite,
    ScriptState* script_state,
    ExceptionState& exception_state) {
  StringKeyframeVector parsed_keyframes =
      ParseKeyframesArgument(element, keyframes, script_state, exception_state);
  if (exception_state.HadException())
    return nullptr;

  composite = ResolveCompositeOperation(composite, parsed_keyframes);

  auto* keyframe_effect_model = MakeGarbageCollected<StringKeyframeEffectModel>(
      parsed_keyframes, composite, LinearTimingFunction::Shared());

  if (!RuntimeEnabledFeatures::WebAnimationsAPIEnabled()) {
    // This should be enforced by the parsing code.
    DCHECK(!HasAdditiveCompositeCSSKeyframe(
        keyframe_effect_model->GetPropertySpecificKeyframeGroups()));
  }

  DCHECK(!exception_state.HadException());
  return keyframe_effect_model;
}

StringKeyframeVector EffectInput::ParseKeyframesArgument(
    Element* element,
    const ScriptValue& keyframes,
    ScriptState* script_state,
    ExceptionState& exception_state) {
  // Per the spec, a null keyframes object maps to a valid but empty sequence.
  v8::Local<v8::Value> keyframes_value = keyframes.V8Value();
  if (keyframes_value->IsNullOrUndefined())
    return {};
  v8::Local<v8::Object> keyframes_obj = keyframes_value.As<v8::Object>();

  // 3. Let method be the result of GetMethod(object, @@iterator).
  v8::Isolate* isolate = script_state->GetIsolate();
  auto script_iterator =
      ScriptIterator::FromIterable(isolate, keyframes_obj, exception_state);
  if (exception_state.HadException())
    return {};

  // TODO(crbug.com/816934): Get spec to specify what parsing context to use.
  Document& document = element
                           ? element->GetDocument()
                           : *LocalDOMWindow::From(script_state)->document();

  // Map logical to physical properties.
  const ComputedStyle* style = element ? element->GetComputedStyle() : nullptr;
  TextDirection text_direction =
      style ? style->Direction() : TextDirection::kLtr;
  WritingMode writing_mode =
      style ? style->GetWritingMode() : WritingMode::kHorizontalTb;

  StringKeyframeVector parsed_keyframes;
  if (script_iterator.IsNull()) {
    parsed_keyframes = ConvertObjectForm(element, document, keyframes_obj,
                                         script_state, exception_state);
  } else {
    parsed_keyframes =
        ConvertArrayForm(element, document, std::move(script_iterator),
                         script_state, exception_state);
  }

  for (wtf_size_t i = 0; i < parsed_keyframes.size(); i++) {
    StringKeyframe* keyframe = parsed_keyframes[i];
    keyframe->SetLogicalPropertyResolutionContext(text_direction, writing_mode);
  }

  if (!ValidatePartialKeyframes(parsed_keyframes)) {
    exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
                                      "Partial keyframes are not supported.");
    return {};
  }
  return parsed_keyframes;
}

EffectModel::CompositeOperation EffectInput::ResolveCompositeOperation(
    EffectModel::CompositeOperation composite,
    const StringKeyframeVector& keyframes) {
  EffectModel::CompositeOperation result = composite;
  for (const Member<StringKeyframe>& keyframe : keyframes) {
    // Replace is always supported, so we can early-exit if and when we have
    // that as our composite value.
    if (result == EffectModel::kCompositeReplace)
      break;
    result = ResolveCompositeOperationForKeyframe(result, keyframe);
  }
  return result;
}
}  // namespace blink
