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); }
void SVGTransformListInterpolationType::composite( UnderlyingValueOwner& underlyingValueOwner, double underlyingFraction, const InterpolationValue& value, double interpolationFraction) const { underlyingValueOwner.set(*this, value); }
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 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); }
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)); } }
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); }
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()); } }