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); }
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; }
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; }