bignum lowestCommonMultiple(const bignum &bn1, const bignum &bn2) { if (bn1.isNegative() != bn2.isNegative()) return lowestCommonMultiple(bn1.absolute(), bn2.absolute()); if (bn1.getDecimalCount() > 0 || bn2.getDecimalCount() > 0) throw error_handler(__FILE__, __LINE__, "Lowest common multiple can only be found with two integers"); if (bn1 == bn2) return bn1; bignum lowest = bn1 < bn2 ? bn1 : bn2; bignum highest = bn1 > bn2 ? bn1 : bn2; if (highest % lowest == 0) return highest; for (int i = 1; lowest >= i; i++) { bignum product_check(highest * i); if (product_check % lowest == 0) return product_check; } throw error_handler(__FILE__, __LINE__, "An error has occurred"); }
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)); }
bool AnimatableRepeatable::usesDefaultInterpolationWith(const AnimatableValue* value) const { const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue>>& fromValues = m_values; const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue>>& toValues = toAnimatableRepeatable(value)->m_values; ASSERT(!fromValues.isEmpty() && !toValues.isEmpty()); size_t size = lowestCommonMultiple(fromValues.size(), toValues.size()); ASSERT(size > 0); for (size_t i = 0; i < size; ++i) { const AnimatableValue* from = fromValues[i % fromValues.size()].get(); const AnimatableValue* to = toValues[i % toValues.size()].get(); // Spec: If a pair of values cannot be interpolated, then the lists are not interpolable. if (AnimatableValue::usesDefaultInterpolation(from, to)) return true; } return false; }
bool AnimatableRepeatable::interpolateLists(const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue>>& fromValues, const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue>>& toValues, double fraction, WillBeHeapVector<RefPtrWillBeMember<AnimatableValue>>& interpolatedValues) { // Interpolation behaviour spec: http://www.w3.org/TR/css3-transitions/#animtype-repeatable-list ASSERT(interpolatedValues.isEmpty()); ASSERT(!fromValues.isEmpty() && !toValues.isEmpty()); size_t size = lowestCommonMultiple(fromValues.size(), toValues.size()); ASSERT(size > 0); for (size_t i = 0; i < size; ++i) { const AnimatableValue* from = fromValues[i % fromValues.size()].get(); const AnimatableValue* to = toValues[i % toValues.size()].get(); // Spec: If a pair of values cannot be interpolated, then the lists are not interpolable. if (AnimatableValue::usesDefaultInterpolation(from, to)) return false; interpolatedValues.append(interpolate(from, to, fraction)); } return true; }
String StylePropertySerializer::backgroundRepeatPropertyValue() const { RefPtr<CSSValue> repeatX = m_propertySet.getPropertyCSSValue(CSSPropertyBackgroundRepeatX); RefPtr<CSSValue> repeatY = m_propertySet.getPropertyCSSValue(CSSPropertyBackgroundRepeatY); if (!repeatX || !repeatY) return String(); if (repeatX->cssValueType() == repeatY->cssValueType() && (repeatX->cssValueType() == CSSValue::CSS_INITIAL || repeatX->cssValueType() == CSSValue::CSS_INHERIT)) { return repeatX->cssText(); } RefPtr<CSSValueList> repeatXList; if (repeatX->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) { repeatXList = CSSValueList::createCommaSeparated(); repeatXList->append(repeatX); } else if (repeatX->cssValueType() == CSSValue::CSS_VALUE_LIST) { repeatXList = toCSSValueList(repeatX.get()); } else { return String(); } RefPtr<CSSValueList> repeatYList; if (repeatY->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) { repeatYList = CSSValueList::createCommaSeparated(); repeatYList->append(repeatY); } else if (repeatY->cssValueType() == CSSValue::CSS_VALUE_LIST) { repeatYList = toCSSValueList(repeatY.get()); } else { return String(); } size_t shorthandLength = lowestCommonMultiple(repeatXList->length(), repeatYList->length()); StringBuilder builder; for (size_t i = 0; i < shorthandLength; ++i) { if (i) builder.appendLiteral(", "); appendBackgroundRepeatValue(builder, *repeatXList->item(i % repeatXList->length()), *repeatYList->item(i % repeatYList->length())); } return builder.toString(); }
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)); } }