PassOwnPtr<InterpolationValue> PathInterpolationFunctions::maybeConvertNeutral(const InterpolationType& type, const UnderlyingValue& underlyingValue, InterpolationType::ConversionCheckers& conversionCheckers) { conversionCheckers.append(UnderlyingPathSegTypesChecker::create(type, underlyingValue)); OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount); result->set(PathArgsIndex, toInterpolableList(underlyingValue->interpolableValue()).get(PathArgsIndex)->cloneAndZero()); result->set(PathNeutralIndex, InterpolableNumber::create(1)); return InterpolationValue::create(type, result.release(), const_cast<NonInterpolableValue*>(underlyingValue->nonInterpolableValue())); // Take ref. }
PassOwnPtr<InterpolationValue> CSSImageListInterpolationType::maybeConvertNeutral(const UnderlyingValue& underlyingValue, ConversionCheckers& conversionCheckers) const { if (!underlyingValue) { conversionCheckers.append(UnderlyingImageListChecker::create(*this, nullptr)); return nullptr; } conversionCheckers.append(UnderlyingImageListChecker::create(*this, underlyingValue->clone())); return underlyingValue->clone(); }
PassOwnPtr<InterpolationValue> SVGTransformListInterpolationType::maybeConvertNeutral(const UnderlyingValue& underlyingValue, ConversionCheckers& conversionCheckers) const { Vector<SVGTransformType> underlyingTypes(toSVGTransformNonInterpolableValue(underlyingValue->nonInterpolableValue())->transformTypes()); conversionCheckers.append(UnderlyingTypesChecker::create(*this, underlyingTypes)); if (underlyingTypes.isEmpty()) return nullptr; OwnPtr<InterpolationValue> result = underlyingValue->clone(); result->mutableComponent().interpolableValue = result->interpolableValue().cloneAndZero(); return result.release(); }
void SVGNumberListInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const { const InterpolableList& list = toInterpolableList(value.interpolableValue()); if (toInterpolableList(underlyingValue->interpolableValue()).length() <= list.length()) padWithZeroes(underlyingValue.mutableComponent().interpolableValue, list.length()); InterpolableList& underlyingList = *toInterpolableList(underlyingValue.mutableComponent().interpolableValue.get()); ASSERT(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); }
void PathInterpolationFunctions::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) { const InterpolableList& list = toInterpolableList(value.interpolableValue()); double neutralComponent = toInterpolableNumber(list.get(PathNeutralIndex))->value(); if (neutralComponent == 0) { underlyingValue.set(&value); return; } ASSERT(pathSegTypesMatch( toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes(), toSVGPathNonInterpolableValue(value.nonInterpolableValue())->pathSegTypes())); underlyingValue.mutableComponent().interpolableValue->scaleAndAdd(neutralComponent, value.interpolableValue()); underlyingValue.mutableComponent().nonInterpolableValue = const_cast<NonInterpolableValue*>(value.nonInterpolableValue()); // Take ref. }
PassOwnPtr<InterpolationValue> InvalidatableInterpolation::convertSingleKeyframe(const PropertySpecificKeyframe& keyframe, const InterpolationEnvironment& environment, const UnderlyingValue& underlyingValue) const { if (keyframe.isNeutral() && !underlyingValue) return nullptr; for (const auto& interpolationType : m_interpolationTypes) { if (keyframe.isNeutral() && underlyingValue->type() != *interpolationType) continue; OwnPtr<InterpolationValue> result = interpolationType->maybeConvertSingle(keyframe, environment, underlyingValue, m_conversionCheckers); if (result) { ASSERT(result->type() == *interpolationType); return result.release(); } } ASSERT(keyframe.isNeutral()); return nullptr; }
void InvalidatableInterpolation::applyStack(const ActiveInterpolations& interpolations, InterpolationEnvironment& environment) { ASSERT(!interpolations.isEmpty()); size_t startingIndex = 0; // Compute the underlying value to composite onto. UnderlyingValue underlyingValue; const InvalidatableInterpolation& firstInterpolation = toInvalidatableInterpolation(*interpolations.at(startingIndex)); if (firstInterpolation.dependsOnUnderlyingValue()) { underlyingValue.set(firstInterpolation.maybeConvertUnderlyingValue(environment)); } else { const InterpolationValue* firstValue = firstInterpolation.ensureValidInterpolation(environment, UnderlyingValue()); // 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->nonInterpolableValue(), environment); } return; } underlyingValue.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)); ASSERT(currentInterpolation.dependsOnUnderlyingValue()); const InterpolationValue* currentValue = currentInterpolation.ensureValidInterpolation(environment, underlyingValue); if (!currentValue) continue; shouldApply = true; currentInterpolation.setFlagIfInheritUsed(environment); double underlyingFraction = currentInterpolation.underlyingFraction(); if (underlyingFraction == 0 || !underlyingValue || underlyingValue->type() != currentValue->type()) underlyingValue.set(currentValue); else currentValue->type().composite(underlyingValue, underlyingFraction, *currentValue); } if (shouldApply && underlyingValue) underlyingValue->type().apply(underlyingValue->interpolableValue(), underlyingValue->nonInterpolableValue(), environment); }
bool InvalidatableInterpolation::isCacheValid(const InterpolationEnvironment& environment, const UnderlyingValue& underlyingValue) 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 (!underlyingValue || !m_cachedValue || m_cachedValue->type() != underlyingValue->type()) return false; } for (const auto& checker : m_conversionCheckers) { if (!checker->isValid(environment, underlyingValue)) return false; } return true; }
PassOwnPtr<PairwisePrimitiveInterpolation> InvalidatableInterpolation::maybeConvertPairwise(const InterpolationEnvironment& environment, const UnderlyingValue& underlyingValue) const { ASSERT(m_currentFraction != 0 && m_currentFraction != 1); for (const auto& interpolationType : m_interpolationTypes) { if ((m_startKeyframe->isNeutral() || m_endKeyframe->isNeutral()) && (!underlyingValue || underlyingValue->type() != *interpolationType)) continue; OwnPtr<PairwisePrimitiveInterpolation> pairwiseConversion = interpolationType->maybeConvertPairwise(*m_startKeyframe, *m_endKeyframe, environment, underlyingValue, m_conversionCheckers); if (pairwiseConversion) { ASSERT(pairwiseConversion->type() == *interpolationType); return pairwiseConversion.release(); } } return nullptr; }
void SVGTransformListInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const { // TODO(suzyh): Implement addition underlyingValue.set(&value); }
bool isValid(const InterpolationEnvironment&, const UnderlyingValue& underlyingValue) const final { if (!underlyingValue && !m_underlyingValue) return true; if (!underlyingValue || !m_underlyingValue) return false; return ListInterpolationFunctions::equalValues(m_underlyingValue->component(), underlyingValue->component(), CSSImageInterpolationType::equalNonInterpolableValues); }
void CSSImageListInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const { underlyingValue.set(&value); }
void CSSLengthInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const { InterpolationComponent& underlyingComponent = underlyingValue.mutableComponent(); underlyingComponent.interpolableValue->scaleAndAdd(underlyingFraction, value.interpolableValue()); underlyingComponent.nonInterpolableValue = CSSLengthNonInterpolableValue::merge(underlyingValue->nonInterpolableValue(), value.nonInterpolableValue()); }