void InvalidatableInterpolation::applyStack(
    const ActiveInterpolations& interpolations,
    InterpolationEnvironment& environment) {
  DCHECK(!interpolations.isEmpty());
  size_t startingIndex = 0;

  // Compute the underlying value to composite onto.
  UnderlyingValueOwner underlyingValueOwner;
  const InvalidatableInterpolation& firstInterpolation =
      toInvalidatableInterpolation(*interpolations.at(startingIndex));
  if (firstInterpolation.dependsOnUnderlyingValue()) {
    underlyingValueOwner.set(
        firstInterpolation.maybeConvertUnderlyingValue(environment));
  } else {
    const TypedInterpolationValue* firstValue =
        firstInterpolation.ensureValidInterpolation(environment,
                                                    underlyingValueOwner);
    // Fast path for replace interpolations that are the only one to apply.
    if (interpolations.size() == 1) {
      if (firstValue) {
        firstInterpolation.setFlagIfInheritUsed(environment);
        firstValue->type().apply(firstValue->interpolableValue(),
                                 firstValue->getNonInterpolableValue(),
                                 environment);
      }
      return;
    }
    underlyingValueOwner.set(firstValue);
    startingIndex++;
  }

  // Composite interpolations onto the underlying value.
  bool shouldApply = false;
  for (size_t i = startingIndex; i < interpolations.size(); i++) {
    const InvalidatableInterpolation& currentInterpolation =
        toInvalidatableInterpolation(*interpolations.at(i));
    DCHECK(currentInterpolation.dependsOnUnderlyingValue());
    const TypedInterpolationValue* currentValue =
        currentInterpolation.ensureValidInterpolation(environment,
                                                      underlyingValueOwner);
    if (!currentValue)
      continue;
    shouldApply = true;
    currentInterpolation.setFlagIfInheritUsed(environment);
    double underlyingFraction = currentInterpolation.underlyingFraction();
    if (underlyingFraction == 0 || !underlyingValueOwner ||
        underlyingValueOwner.type() != currentValue->type())
      underlyingValueOwner.set(currentValue);
    else
      currentValue->type().composite(underlyingValueOwner, underlyingFraction,
                                     currentValue->value(),
                                     currentInterpolation.m_currentFraction);
  }

  if (shouldApply && underlyingValueOwner)
    underlyingValueOwner.type().apply(
        *underlyingValueOwner.value().interpolableValue,
        underlyingValueOwner.value().nonInterpolableValue.get(), environment);
}
Beispiel #2
0
void PathInterpolationFunctions::composite(
    UnderlyingValueOwner& underlyingValueOwner,
    double underlyingFraction,
    const InterpolationType& type,
    const InterpolationValue& value) {
  const InterpolableList& list = toInterpolableList(*value.interpolableValue);
  double neutralComponent =
      toInterpolableNumber(list.get(PathNeutralIndex))->value();

  if (neutralComponent == 0) {
    underlyingValueOwner.set(type, value);
    return;
  }

  DCHECK(pathSegTypesMatch(
      toSVGPathNonInterpolableValue(
          *underlyingValueOwner.value().nonInterpolableValue)
          .pathSegTypes(),
      toSVGPathNonInterpolableValue(*value.nonInterpolableValue)
          .pathSegTypes()));
  underlyingValueOwner.mutableValue().interpolableValue->scaleAndAdd(
      neutralComponent, *value.interpolableValue);
  underlyingValueOwner.mutableValue().nonInterpolableValue =
      value.nonInterpolableValue.get();
}
void CSSClipInterpolationType::composite(UnderlyingValueOwner& underlyingValueOwner, double underlyingFraction, const InterpolationValue& value, double interpolationFraction) const
{
    const ClipAutos& underlyingAutos = toCSSClipNonInterpolableValue(*underlyingValueOwner.value().nonInterpolableValue).clipAutos();
    const ClipAutos& autos = toCSSClipNonInterpolableValue(*value.nonInterpolableValue).clipAutos();
    if (underlyingAutos == autos)
        underlyingValueOwner.mutableValue().interpolableValue->scaleAndAdd(underlyingFraction, *value.interpolableValue);
    else
        underlyingValueOwner.set(*this, value);
}
void CSSBasicShapeInterpolationType::composite(UnderlyingValueOwner& underlyingValueOwner, double underlyingFraction, const InterpolationValue& value, double interpolationFraction) const
{
    if (!BasicShapeInterpolationFunctions::shapesAreCompatible(*underlyingValueOwner.value().nonInterpolableValue, *value.nonInterpolableValue)) {
        underlyingValueOwner.set(*this, value);
        return;
    }

    underlyingValueOwner.mutableValue().interpolableValue->scaleAndAdd(underlyingFraction, *value.interpolableValue);
}
void CSSImageSliceInterpolationType::composite(UnderlyingValueOwner& underlyingValueOwner, double underlyingFraction, const InterpolationValue& value, double interpolationFraction) const
{
    const SliceTypes& underlyingTypes = toCSSImageSliceNonInterpolableValue(*underlyingValueOwner.value().nonInterpolableValue).types();
    const SliceTypes& types = toCSSImageSliceNonInterpolableValue(*value.nonInterpolableValue).types();

    if (underlyingTypes == types)
        underlyingValueOwner.mutableValue().interpolableValue->scaleAndAdd(underlyingFraction, *value.interpolableValue);
    else
        underlyingValueOwner.set(*this, value);
}
void ListInterpolationFunctions::composite(UnderlyingValueOwner& underlyingValueOwner, double underlyingFraction, const InterpolationType& type, const InterpolationValue& value, NonInterpolableValuesAreCompatibleCallback nonInterpolableValuesAreCompatible, CompositeItemCallback compositeItem)
{
    size_t underlyingLength = toInterpolableList(*underlyingValueOwner.value().interpolableValue).length();
    if (underlyingLength == 0) {
        ASSERT(!underlyingValueOwner.value().nonInterpolableValue);
        underlyingValueOwner.set(type, value);
        return;
    }

    const InterpolableList& interpolableList = toInterpolableList(*value.interpolableValue);
    size_t valueLength = interpolableList.length();
    if (valueLength == 0) {
        ASSERT(!value.nonInterpolableValue);
        underlyingValueOwner.mutableValue().interpolableValue->scale(underlyingFraction);
        return;
    }

    const NonInterpolableList& nonInterpolableList = toNonInterpolableList(*value.nonInterpolableValue);
    size_t newLength = lowestCommonMultiple(underlyingLength, valueLength);
    if (!nonInterpolableListsAreCompatible(toNonInterpolableList(*underlyingValueOwner.value().nonInterpolableValue), nonInterpolableList, newLength, nonInterpolableValuesAreCompatible)) {
        underlyingValueOwner.set(type, value);
        return;
    }

    InterpolationValue& underlyingValue = underlyingValueOwner.mutableValue();
    if (underlyingLength < newLength)
        repeatToLength(underlyingValue, newLength);

    InterpolableList& underlyingInterpolableList = toInterpolableList(*underlyingValue.interpolableValue);
    NonInterpolableList& underlyingNonInterpolableList = toNonInterpolableList(*underlyingValue.nonInterpolableValue);
    for (size_t i = 0; i < newLength; i++) {
        compositeItem(
            underlyingInterpolableList.getMutable(i),
            underlyingNonInterpolableList.getMutable(i),
            underlyingFraction,
            *interpolableList.get(i % valueLength),
            nonInterpolableList.get(i % valueLength));
    }
}
Beispiel #7
0
void CSSRotateInterpolationType::composite(
    UnderlyingValueOwner& underlyingValueOwner,
    double underlyingFraction,
    const InterpolationValue& value,
    double interpolationFraction) const {
  CSSRotateNonInterpolableValue& underlyingNonInterpolableValue =
      toCSSRotateNonInterpolableValue(
          *underlyingValueOwner.value().nonInterpolableValue);
  const CSSRotateNonInterpolableValue& nonInterpolableValue =
      toCSSRotateNonInterpolableValue(*value.nonInterpolableValue);
  double progress = toInterpolableNumber(*value.interpolableValue).value();
  underlyingValueOwner.mutableValue().nonInterpolableValue =
      underlyingNonInterpolableValue.composite(nonInterpolableValue, progress);
}
Beispiel #8
0
void CSSFilterListInterpolationType::composite(
    UnderlyingValueOwner& underlyingValueOwner,
    double underlyingFraction,
    const InterpolationValue& value,
    double interpolationFraction) const {
  const NonInterpolableList& underlyingNonInterpolableList =
      toNonInterpolableList(*underlyingValueOwner.value().nonInterpolableValue);
  const NonInterpolableList& nonInterpolableList =
      toNonInterpolableList(*value.nonInterpolableValue);
  size_t underlyingLength = underlyingNonInterpolableList.length();
  size_t length = nonInterpolableList.length();

  for (size_t i = 0; i < underlyingLength && i < length; i++) {
    if (!FilterInterpolationFunctions::filtersAreCompatible(
            *underlyingNonInterpolableList.get(i),
            *nonInterpolableList.get(i))) {
      underlyingValueOwner.set(*this, value);
      return;
    }
  }

  InterpolableList& underlyingInterpolableList = toInterpolableList(
      *underlyingValueOwner.mutableValue().interpolableValue);
  const InterpolableList& interpolableList =
      toInterpolableList(*value.interpolableValue);
  DCHECK_EQ(underlyingLength, underlyingInterpolableList.length());
  DCHECK_EQ(length, interpolableList.length());

  for (size_t i = 0; i < length && i < underlyingLength; i++)
    underlyingInterpolableList.getMutable(i)->scaleAndAdd(
        underlyingFraction, *interpolableList.get(i));

  if (length <= underlyingLength)
    return;

  std::unique_ptr<InterpolableList> extendedInterpolableList =
      InterpolableList::create(length);
  for (size_t i = 0; i < length; i++) {
    if (i < underlyingLength)
      extendedInterpolableList->set(
          i, std::move(underlyingInterpolableList.getMutable(i)));
    else
      extendedInterpolableList->set(i, interpolableList.get(i)->clone());
  }
  underlyingValueOwner.mutableValue().interpolableValue =
      std::move(extendedInterpolableList);
  // const_cast to take a ref.
  underlyingValueOwner.mutableValue().nonInterpolableValue =
      const_cast<NonInterpolableValue*>(value.nonInterpolableValue.get());
}
void SVGPointListInterpolationType::composite(
    UnderlyingValueOwner& underlyingValueOwner,
    double underlyingFraction,
    const InterpolationValue& value,
    double interpolationFraction) const {
  size_t startLength =
      toInterpolableList(*underlyingValueOwner.value().interpolableValue)
          .length();
  size_t endLength = toInterpolableList(*value.interpolableValue).length();
  if (startLength == endLength)
    InterpolationType::composite(underlyingValueOwner, underlyingFraction,
                                 value, interpolationFraction);
  else
    underlyingValueOwner.set(*this, value);
}
bool InvalidatableInterpolation::isCacheValid(
    const InterpolationEnvironment& environment,
    const UnderlyingValueOwner& underlyingValueOwner) const {
  if (!m_isCached)
    return false;
  if (isNeutralKeyframeActive()) {
    if (m_cachedPairConversion && m_cachedPairConversion->isFlip())
      return false;
    // Pairwise interpolation can never happen between different
    // InterpolationTypes, neutral values always represent the underlying value.
    if (!underlyingValueOwner || !m_cachedValue ||
        m_cachedValue->type() != underlyingValueOwner.type())
      return false;
  }
  for (const auto& checker : m_conversionCheckers) {
    if (!checker->isValid(environment, underlyingValueOwner.value()))
      return false;
  }
  return true;
}
void CSSBorderImageLengthBoxInterpolationType::composite(
    UnderlyingValueOwner& underlyingValueOwner,
    double underlyingFraction,
    const InterpolationValue& value,
    double interpolationFraction) const {
  const SideNumbers& underlyingSideNumbers =
      toCSSBorderImageLengthBoxNonInterpolableValue(
          *underlyingValueOwner.value().nonInterpolableValue)
          .sideNumbers();
  const auto& nonInterpolableValue =
      toCSSBorderImageLengthBoxNonInterpolableValue(
          *value.nonInterpolableValue);
  const SideNumbers& sideNumbers = nonInterpolableValue.sideNumbers();

  if (underlyingSideNumbers != sideNumbers) {
    underlyingValueOwner.set(*this, value);
    return;
  }

  InterpolationValue& underlyingValue = underlyingValueOwner.mutableValue();
  InterpolableList& underlyingList =
      toInterpolableList(*underlyingValue.interpolableValue);
  Vector<RefPtr<NonInterpolableValue>>& underlyingSideNonInterpolableValues =
      toCSSBorderImageLengthBoxNonInterpolableValue(
          *underlyingValue.nonInterpolableValue)
          .sideNonInterpolableValues();
  const InterpolableList& list = toInterpolableList(*value.interpolableValue);
  const Vector<RefPtr<NonInterpolableValue>>& sideNonInterpolableValues =
      nonInterpolableValue.sideNonInterpolableValues();

  for (size_t i = 0; i < SideIndexCount; i++) {
    if (sideNumbers.isNumber[i])
      underlyingList.getMutable(i)->scaleAndAdd(underlyingFraction,
                                                *list.get(i));
    else
      LengthInterpolationFunctions::composite(
          underlyingList.getMutable(i), underlyingSideNonInterpolableValues[i],
          underlyingFraction, *list.get(i), sideNonInterpolableValues[i].get());
  }
}
Beispiel #12
0
void SVGNumberListInterpolationType::composite(
    UnderlyingValueOwner& underlyingValueOwner,
    double underlyingFraction,
    const InterpolationValue& value,
    double interpolationFraction) const {
    const InterpolableList& list = toInterpolableList(*value.interpolableValue);

    if (toInterpolableList(*underlyingValueOwner.value().interpolableValue)
            .length() <= list.length())
        padWithZeroes(underlyingValueOwner.mutableValue().interpolableValue,
                      list.length());

    InterpolableList& underlyingList = toInterpolableList(
                                           *underlyingValueOwner.mutableValue().interpolableValue);

    DCHECK_GE(underlyingList.length(), list.length());
    size_t i = 0;
    for (; i < list.length(); i++)
        underlyingList.getMutable(i)->scaleAndAdd(underlyingFraction, *list.get(i));
    for (; i < underlyingList.length(); i++)
        underlyingList.getMutable(i)->scale(underlyingFraction);
}
std::unique_ptr<TypedInterpolationValue>
InvalidatableInterpolation::convertSingleKeyframe(
    const PropertySpecificKeyframe& keyframe,
    const InterpolationEnvironment& environment,
    const UnderlyingValueOwner& underlyingValueOwner) const {
  if (keyframe.isNeutral() && !underlyingValueOwner)
    return nullptr;
  for (const auto& interpolationType : m_interpolationTypes) {
    if (keyframe.isNeutral() &&
        underlyingValueOwner.type() != *interpolationType)
      continue;
    ConversionCheckers conversionCheckers;
    InterpolationValue result = interpolationType->maybeConvertSingle(
        keyframe, environment, underlyingValueOwner.value(),
        conversionCheckers);
    addConversionCheckers(*interpolationType, conversionCheckers);
    if (result)
      return TypedInterpolationValue::create(
          *interpolationType, std::move(result.interpolableValue),
          result.nonInterpolableValue.release());
  }
  DCHECK(keyframe.isNeutral());
  return nullptr;
}
std::unique_ptr<PairwisePrimitiveInterpolation>
InvalidatableInterpolation::maybeConvertPairwise(
    const InterpolationEnvironment& environment,
    const UnderlyingValueOwner& underlyingValueOwner) const {
  DCHECK(m_currentFraction != 0 && m_currentFraction != 1);
  for (const auto& interpolationType : m_interpolationTypes) {
    if ((m_startKeyframe->isNeutral() || m_endKeyframe->isNeutral()) &&
        (!underlyingValueOwner ||
         underlyingValueOwner.type() != *interpolationType))
      continue;
    ConversionCheckers conversionCheckers;
    PairwiseInterpolationValue result = interpolationType->maybeConvertPairwise(
        *m_startKeyframe, *m_endKeyframe, environment,
        underlyingValueOwner.value(), conversionCheckers);
    addConversionCheckers(*interpolationType, conversionCheckers);
    if (result) {
      return PairwisePrimitiveInterpolation::create(
          *interpolationType, std::move(result.startInterpolableValue),
          std::move(result.endInterpolableValue),
          result.nonInterpolableValue.release());
    }
  }
  return nullptr;
}
void CSSMotionRotationInterpolationType::composite(UnderlyingValueOwner& underlyingValueOwner, double underlyingFraction, const InterpolationValue& value) const
{
    const MotionRotationType& underlyingType = toCSSMotionRotationNonInterpolableValue(*underlyingValueOwner.value().nonInterpolableValue).rotationType();
    const MotionRotationType& rotationType = toCSSMotionRotationNonInterpolableValue(*value.nonInterpolableValue).rotationType();
    if (underlyingType == rotationType)
        underlyingValueOwner.mutableValue().interpolableValue->scaleAndAdd(underlyingFraction, *value.interpolableValue);
    else
        underlyingValueOwner.set(*this, value);
}