text: // Copyright 2015 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLATION_TYPE_H_
  #define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLATION_TYPE_H_
  
  #include <memory>
  
  #include "base/macros.h"
  #include "third_party/blink/renderer/core/animation/interpolation_value.h"
  #include "third_party/blink/renderer/core/animation/keyframe.h"
  #include "third_party/blink/renderer/core/animation/pairwise_interpolation_value.h"
  #include "third_party/blink/renderer/core/animation/primitive_interpolation.h"
  #include "third_party/blink/renderer/core/animation/property_handle.h"
  #include "third_party/blink/renderer/core/animation/underlying_value_owner.h"
  #include "third_party/blink/renderer/platform/heap/handle.h"
  #include "third_party/blink/renderer/platform/wtf/allocator.h"
  
  namespace blink {
  
  class InterpolationEnvironment;
  
  // Subclasses of InterpolationType implement the logic for a specific value type
  // of a specific PropertyHandle to:
  // - Convert PropertySpecificKeyframe values to (Pairwise)?InterpolationValues:
  // maybeConvertPairwise() and maybeConvertSingle()
  // - Convert the target Element's property value to an InterpolationValue:
  // maybeConvertUnderlyingValue()
  // - Apply an InterpolationValue to a target Element's property: apply().
  class InterpolationType {
    USING_FAST_MALLOC(InterpolationType);
  
   public:
    virtual ~InterpolationType() = default;
  
    PropertyHandle GetProperty() const { return property_; }
  
    // ConversionCheckers are returned from calls to maybeConvertPairwise() and
    // maybeConvertSingle() to enable the caller to check whether the result is
    // still valid given changes in the InterpolationEnvironment and underlying
    // InterpolationValue.
    class ConversionChecker {
      USING_FAST_MALLOC(ConversionChecker);
  
     public:
      virtual ~ConversionChecker() = default;
      void SetType(const InterpolationType& type) { type_ = &type; }
      const InterpolationType& GetType() const { return *type_; }
      virtual bool IsValid(const InterpolationEnvironment&,
                           const InterpolationValue& underlying) const = 0;
  
     protected:
      ConversionChecker() : type_(nullptr) {}
      const InterpolationType* type_;
      DISALLOW_COPY_AND_ASSIGN(ConversionChecker);
    };
    using ConversionCheckers = Vector<std::unique_ptr<ConversionChecker>>;
  
    virtual PairwiseInterpolationValue MaybeConvertPairwise(
        const PropertySpecificKeyframe& start_keyframe,
        const PropertySpecificKeyframe& end_keyframe,
        const InterpolationEnvironment& environment,
        const InterpolationValue& underlying,
        ConversionCheckers& conversion_checkers) const {
      InterpolationValue start = MaybeConvertSingle(
          start_keyframe, environment, underlying, conversion_checkers);
      if (!start)
        return nullptr;
      InterpolationValue end = MaybeConvertSingle(
          end_keyframe, environment, underlying, conversion_checkers);
      if (!end)
        return nullptr;
      return MaybeMergeSingles(std::move(start), std::move(end));
    }
  
    virtual InterpolationValue MaybeConvertSingle(
        const PropertySpecificKeyframe&,
        const InterpolationEnvironment&,
        const InterpolationValue& underlying,
        ConversionCheckers&) const = 0;
  
    virtual PairwiseInterpolationValue MaybeMergeSingles(
        InterpolationValue&& start,
        InterpolationValue&& end) const {
      DCHECK(!start.non_interpolable_value);
      DCHECK(!end.non_interpolable_value);
      return PairwiseInterpolationValue(std::move(start.interpolable_value),
                                        std::move(end.interpolable_value),
                                        nullptr);
    }
  
    virtual InterpolationValue MaybeConvertUnderlyingValue(
        const InterpolationEnvironment&) const = 0;
  
    virtual void Composite(UnderlyingValueOwner& underlying_value_owner,
                           double underlying_fraction,
                           const InterpolationValue& value,
                           double interpolation_fraction) const {
      DCHECK(!underlying_value_owner.Value().non_interpolable_value);
      DCHECK(!value.non_interpolable_value);
      underlying_value_owner.MutableValue().interpolable_value->ScaleAndAdd(
          underlying_fraction, *value.interpolable_value);
    }
  
    virtual void Apply(const InterpolableValue&,
                       const NonInterpolableValue*,
                       InterpolationEnvironment&) const = 0;
  
    // Implement reference equality checking via pointer equality checking as
    // these are singletons.
    bool operator==(const InterpolationType& other) const {
      return this == &other;
    }
    bool operator!=(const InterpolationType& other) const {
      return this != &other;
    }
  
   protected:
    explicit InterpolationType(PropertyHandle property) : property_(property) {}
  
    const PropertyHandle property_;
    DISALLOW_COPY_AND_ASSIGN(InterpolationType);
  };
  
  }  // namespace blink
  
  #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLATION_TYPE_H_
  