bool ListInterpolationFunctions::equalValues(const InterpolationValue& a, const InterpolationValue& b, EqualNonInterpolableValuesCallback equalNonInterpolableValues) { if (!a && !b) return true; if (!a || !b) return false; const InterpolableList& interpolableListA = toInterpolableList(*a.interpolableValue); const InterpolableList& interpolableListB = toInterpolableList(*b.interpolableValue); if (interpolableListA.length() != interpolableListB.length()) return false; size_t length = interpolableListA.length(); if (length == 0) return true; const NonInterpolableList& nonInterpolableListA = toNonInterpolableList(*a.nonInterpolableValue); const NonInterpolableList& nonInterpolableListB = toNonInterpolableList(*b.nonInterpolableValue); for (size_t i = 0; i < length; i++) { if (!equalNonInterpolableValues(nonInterpolableListA.get(i), nonInterpolableListB.get(i))) return false; } return true; }
PairwiseInterpolationValue ListInterpolationFunctions::mergeSingleConversions(InterpolationValue& start, InterpolationValue& end, MergeSingleItemConversionsCallback mergeSingleItemConversions) { size_t startLength = toInterpolableList(*start.interpolableValue).length(); size_t endLength = toInterpolableList(*end.interpolableValue).length(); if (startLength == 0 && endLength == 0) { return PairwiseInterpolationValue( start.interpolableValue.release(), end.interpolableValue.release(), nullptr); } if (startLength == 0) { OwnPtr<InterpolableValue> startInterpolableValue = end.interpolableValue->cloneAndZero(); return PairwiseInterpolationValue( startInterpolableValue.release(), end.interpolableValue.release(), end.nonInterpolableValue.release()); } if (endLength == 0) { OwnPtr<InterpolableValue> endInterpolableValue = start.interpolableValue->cloneAndZero(); return PairwiseInterpolationValue( start.interpolableValue.release(), endInterpolableValue.release(), start.nonInterpolableValue.release()); } size_t finalLength = lowestCommonMultiple(startLength, endLength); OwnPtr<InterpolableList> resultStartInterpolableList = InterpolableList::create(finalLength); OwnPtr<InterpolableList> resultEndInterpolableList = InterpolableList::create(finalLength); Vector<RefPtr<NonInterpolableValue>> resultNonInterpolableValues(finalLength); InterpolableList& startInterpolableList = toInterpolableList(*start.interpolableValue); InterpolableList& endInterpolableList = toInterpolableList(*end.interpolableValue); NonInterpolableList& startNonInterpolableList = toNonInterpolableList(*start.nonInterpolableValue); NonInterpolableList& endNonInterpolableList = toNonInterpolableList(*end.nonInterpolableValue); for (size_t i = 0; i < finalLength; i++) { InterpolationValue start(startInterpolableList.get(i % startLength)->clone(), startNonInterpolableList.get(i % startLength)); InterpolationValue end(endInterpolableList.get(i % endLength)->clone(), endNonInterpolableList.get(i % endLength)); PairwiseInterpolationValue result = mergeSingleItemConversions(start, end); if (!result) return nullptr; resultStartInterpolableList->set(i, result.startInterpolableValue.release()); resultEndInterpolableList->set(i, result.endInterpolableValue.release()); resultNonInterpolableValues[i] = result.nonInterpolableValue.release(); } return PairwiseInterpolationValue( resultStartInterpolableList.release(), resultEndInterpolableList.release(), NonInterpolableList::create(resultNonInterpolableValues)); }
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()); }
PairwiseInterpolationValue CSSFilterListInterpolationType::maybeMergeSingles( InterpolationValue&& start, InterpolationValue&& end) const { NonInterpolableList& startNonInterpolableList = toNonInterpolableList(*start.nonInterpolableValue); NonInterpolableList& endNonInterpolableList = toNonInterpolableList(*end.nonInterpolableValue); size_t startLength = startNonInterpolableList.length(); size_t endLength = endNonInterpolableList.length(); for (size_t i = 0; i < startLength && i < endLength; i++) { if (!FilterInterpolationFunctions::filtersAreCompatible( *startNonInterpolableList.get(i), *endNonInterpolableList.get(i))) return nullptr; } if (startLength == endLength) return PairwiseInterpolationValue(std::move(start.interpolableValue), std::move(end.interpolableValue), start.nonInterpolableValue.release()); // Extend the shorter InterpolableList with neutral values that are compatible // with corresponding filters in the longer list. InterpolationValue& shorter = startLength < endLength ? start : end; InterpolationValue& longer = startLength < endLength ? end : start; size_t shorterLength = toNonInterpolableList(*shorter.nonInterpolableValue).length(); size_t longerLength = toNonInterpolableList(*longer.nonInterpolableValue).length(); InterpolableList& shorterInterpolableList = toInterpolableList(*shorter.interpolableValue); const NonInterpolableList& longerNonInterpolableList = toNonInterpolableList(*longer.nonInterpolableValue); std::unique_ptr<InterpolableList> extendedInterpolableList = InterpolableList::create(longerLength); for (size_t i = 0; i < longerLength; i++) { if (i < shorterLength) extendedInterpolableList->set( i, std::move(shorterInterpolableList.getMutable(i))); else extendedInterpolableList->set( i, FilterInterpolationFunctions::createNoneValue( *longerNonInterpolableList.get(i))); } shorter.interpolableValue = std::move(extendedInterpolableList); return PairwiseInterpolationValue(std::move(start.interpolableValue), std::move(end.interpolableValue), longer.nonInterpolableValue.release()); }
InterpolationValue CSSFilterListInterpolationType::maybeConvertNeutral( const InterpolationValue& underlying, ConversionCheckers& conversionCheckers) const { // const_cast for taking refs. NonInterpolableList& nonInterpolableList = const_cast<NonInterpolableList&>( toNonInterpolableList(*underlying.nonInterpolableValue)); conversionCheckers.push_back( UnderlyingFilterListChecker::create(&nonInterpolableList)); return InterpolationValue(underlying.interpolableValue->cloneAndZero(), &nonInterpolableList); }
static PassRefPtr<ShadowList> createShadowList(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, const StyleResolverState& state) { const InterpolableList& interpolableList = toInterpolableList(interpolableValue); size_t length = interpolableList.length(); if (length == 0) return nullptr; const NonInterpolableList& nonInterpolableList = toNonInterpolableList(*nonInterpolableValue); ShadowDataVector shadows; for (size_t i = 0; i < length; i++) shadows.append(ShadowInterpolationFunctions::createShadowData(*interpolableList.get(i), nonInterpolableList.get(i), state)); return ShadowList::adopt(shadows); }
void CSSImageListInterpolationType::apply(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const { const InterpolableList& interpolableList = toInterpolableList(interpolableValue); const size_t length = interpolableList.length(); ASSERT(length > 0); const NonInterpolableList& nonInterpolableList = toNonInterpolableList(*nonInterpolableValue); ASSERT(nonInterpolableList.length() == length); StyleImageList imageList(length); for (size_t i = 0; i < length; i++) imageList[i] = CSSImageInterpolationType::resolveStyleImage(cssProperty(), *interpolableList.get(i), nonInterpolableList.get(i), environment.state()); ImageListPropertyFunctions::setImageList(cssProperty(), *environment.state().style(), imageList); }
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 CSSLengthListInterpolationType::apply(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const { const InterpolableList& interpolableList = toInterpolableList(interpolableValue); const size_t length = interpolableList.length(); ASSERT(length > 0); const NonInterpolableList& nonInterpolableList = toNonInterpolableList(*nonInterpolableValue); ASSERT(nonInterpolableList.length() == length); Vector<Length> result(length); for (size_t i = 0; i < length; i++) { result[i] = CSSLengthInterpolationType::resolveInterpolableLength( *interpolableList.get(i), nonInterpolableList.get(i), environment.state().cssToLengthConversionData(), m_valueRange); } LengthListPropertyFunctions::setLengthList(cssProperty(), *environment.state().style(), std::move(result)); }
static void repeatToLength(InterpolationValue& value, size_t length) { InterpolableList& interpolableList = toInterpolableList(*value.interpolableValue); NonInterpolableList& nonInterpolableList = toNonInterpolableList(*value.nonInterpolableValue); size_t currentLength = interpolableList.length(); ASSERT(currentLength > 0); if (currentLength == length) return; ASSERT(currentLength < length); OwnPtr<InterpolableList> newInterpolableList = InterpolableList::create(length); Vector<RefPtr<NonInterpolableValue>> newNonInterpolableValues(length); for (size_t i = length; i-- > 0;) { newInterpolableList->set(i, i < currentLength ? interpolableList.getMutable(i).release() : interpolableList.get(i % currentLength)->clone()); newNonInterpolableValues[i] = nonInterpolableList.get(i % currentLength); } value.interpolableValue = newInterpolableList.release(); value.nonInterpolableValue = NonInterpolableList::create(newNonInterpolableValues); }
void CSSFilterListInterpolationType::apply( const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const { const InterpolableList& interpolableList = toInterpolableList(interpolableValue); const NonInterpolableList& nonInterpolableList = toNonInterpolableList(*nonInterpolableValue); size_t length = interpolableList.length(); DCHECK_EQ(length, nonInterpolableList.length()); FilterOperations filterOperations; filterOperations.operations().reserveCapacity(length); for (size_t i = 0; i < length; i++) filterOperations.operations().push_back( FilterInterpolationFunctions::createFilter(*interpolableList.get(i), *nonInterpolableList.get(i), environment.state())); FilterListPropertyFunctions::setFilterList( cssProperty(), *environment.state().style(), std::move(filterOperations)); }