PassRefPtrWillBeRawPtr<CSSFunctionValue> FilterStyleInterpolation::fromInterpolableValue(const InterpolableValue& value, CSSValueID functionType, InterpolationRange) { const InterpolableList& list = toInterpolableList(value); size_t length = list.length(); RefPtrWillBeRawPtr<CSSFunctionValue> result = CSSFunctionValue::create(functionType); for (size_t i = 0; i < length; ++i) { switch (functionType) { case CSSValueGrayscale: case CSSValueInvert: case CSSValueOpacity: case CSSValueSepia: result->append(CSSPrimitiveValue::create(clampTo<double>(toInterpolableNumber(list.get(i))->value(), 0, 1), CSSPrimitiveValue::UnitType::Number)); break; case CSSValueBrightness: case CSSValueContrast: case CSSValueSaturate: result->append(CSSPrimitiveValue::create(clampTo<double>(toInterpolableNumber(list.get(i))->value(), 0), CSSPrimitiveValue::UnitType::Number)); break; case CSSValueHueRotate: result->append(CSSPrimitiveValue::create(toInterpolableNumber(list.get(i))->value(), CSSPrimitiveValue::UnitType::Degrees)); break; case CSSValueBlur: result->append(LengthStyleInterpolation::fromInterpolableValue(*list.get(i), RangeNonNegative)); break; case CSSValueDropShadow: case CSSValueUrl: default: ASSERT_NOT_REACHED(); break; } } return result.release(); }
PassRefPtr<CSSValue> LengthStyleInterpolation::interpolableValueToLength(InterpolableValue* value, ValueRange range) { InterpolableList* listValue = toInterpolableList(value); unsigned unitCount = 0; for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { const InterpolableNumber* subValue = toInterpolableNumber(listValue->get(i)); if (subValue->value()) { unitCount++; } } switch (unitCount) { case 0: return CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX); case 1: for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { const InterpolableNumber* subValue = toInterpolableNumber(listValue->get(i)); double value = subValue->value(); if (value) { if (range == ValueRangeNonNegative && value < 0) value = 0; return CSSPrimitiveValue::create(value, toUnitType(i)); } } ASSERT_NOT_REACHED(); default: return CSSPrimitiveValue::create(CSSCalcValue::create(constructCalcExpression(nullptr, listValue, 0), range)); } }
static Length resolveInterpolablePixelsOrPercentageLength(const InterpolableList& values, bool hasPercentage, ValueRange range, double zoom) { ASSERT(isPixelsOrPercentOnly(values)); double pixels = toInterpolableNumber(values.get(CSSPrimitiveValue::UnitTypePixels))->value() * zoom; double percentage = toInterpolableNumber(values.get(CSSPrimitiveValue::UnitTypePercentage))->value(); return createLength(pixels, percentage, hasPercentage, range); }
PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGNumberOptionalNumberInterpolationType::appliedSVGValue(const InterpolableValue& interpolableValue, const NonInterpolableValue*) const { const InterpolableList& list = toInterpolableList(interpolableValue); return SVGNumberOptionalNumber::create( SVGNumber::create(toInterpolableNumber(list.get(0))->value()), SVGNumber::create(toInterpolableNumber(list.get(1))->value())); }
PassRefPtrWillBeRawPtr<SVGRect> RectSVGInterpolation::fromInterpolableValue(const InterpolableValue& value) { const InterpolableList& list = toInterpolableList(value); RefPtrWillBeRawPtr<SVGRect> result = SVGRect::create(); result->setX(toInterpolableNumber(list.get(0))->value()); result->setY(toInterpolableNumber(list.get(1))->value()); result->setWidth(toInterpolableNumber(list.get(2))->value()); result->setHeight(toInterpolableNumber(list.get(3))->value()); return result; }
PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGRectInterpolationType::appliedSVGValue(const InterpolableValue& interpolableValue, const NonInterpolableValue*) const { const InterpolableList& list = toInterpolableList(interpolableValue); RefPtrWillBeRawPtr<SVGRect> result = SVGRect::create(); result->setX(toInterpolableNumber(list.get(RectX))->value()); result->setY(toInterpolableNumber(list.get(RectY))->value()); result->setWidth(toInterpolableNumber(list.get(RectWidth))->value()); result->setHeight(toInterpolableNumber(list.get(RectHeight))->value()); return result; }
void LengthInterpolationFunctions::subtractFromOneHundredPercent( InterpolationValue& result) { InterpolableList& list = toInterpolableList(*result.interpolableValue); for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { double value = -toInterpolableNumber(*list.get(i)).value(); if (i == CSSPrimitiveValue::UnitTypePercentage) value += 100; toInterpolableNumber(*list.getMutable(i)).set(value); } result.nonInterpolableValue = CSSLengthNonInterpolableValue::create(true); }
void InterpolableNumber::interpolate(const InterpolableValue &to, const double progress, InterpolableValue& result) const { const InterpolableNumber& toNumber = toInterpolableNumber(to); InterpolableNumber& resultNumber = toInterpolableNumber(result); if (progress == 0 || m_value == toNumber.m_value) resultNumber.m_value = m_value; else if (progress == 1) resultNumber.m_value = toNumber.m_value; else resultNumber.m_value = m_value * (1 - progress) + toNumber.m_value * progress; }
FilterOperation* FilterInterpolationFunctions::createFilter( const InterpolableValue& interpolableValue, const NonInterpolableValue& untypedNonInterpolableValue, const StyleResolverState& state) { const FilterNonInterpolableValue& nonInterpolableValue = toFilterNonInterpolableValue(untypedNonInterpolableValue); FilterOperation::OperationType type = nonInterpolableValue.type(); switch (type) { case FilterOperation::GRAYSCALE: case FilterOperation::HUE_ROTATE: case FilterOperation::SATURATE: case FilterOperation::SEPIA: { double value = clampParameter(toInterpolableNumber(interpolableValue).value(), type); return BasicColorMatrixFilterOperation::create(value, type); } case FilterOperation::BRIGHTNESS: case FilterOperation::CONTRAST: case FilterOperation::INVERT: case FilterOperation::OPACITY: { double value = clampParameter(toInterpolableNumber(interpolableValue).value(), type); return BasicComponentTransferFilterOperation::create(value, type); } case FilterOperation::BLUR: { Length stdDeviation = LengthInterpolationFunctions::createLength( interpolableValue, nonInterpolableValue.typeNonInterpolableValue(), state.cssToLengthConversionData(), ValueRangeNonNegative); return BlurFilterOperation::create(stdDeviation); } case FilterOperation::DROP_SHADOW: { ShadowData shadowData = ShadowInterpolationFunctions::createShadowData( interpolableValue, nonInterpolableValue.typeNonInterpolableValue(), state); Color color = shadowData.color().isCurrentColor() ? Color::black : shadowData.color().getColor(); return DropShadowFilterOperation::create( IntPoint(shadowData.x(), shadowData.y()), shadowData.blur(), color); } default: NOTREACHED(); return nullptr; } }
TEST_F(AnimationInterpolableValueTest, ScaleAndAddLists) { OwnPtrWillBeRawPtr<InterpolableList> baseList = InterpolableList::create(3); baseList->set(0, InterpolableNumber::create(5)); baseList->set(1, InterpolableNumber::create(10)); baseList->set(2, InterpolableNumber::create(15)); OwnPtrWillBeRawPtr<InterpolableList> addList = InterpolableList::create(3); addList->set(0, InterpolableNumber::create(1)); addList->set(1, InterpolableNumber::create(2)); addList->set(2, InterpolableNumber::create(3)); scaleAndAdd(*baseList, 2, *addList); EXPECT_FLOAT_EQ(11, toInterpolableNumber(baseList->get(0))->value()); EXPECT_FLOAT_EQ(22, toInterpolableNumber(baseList->get(1))->value()); EXPECT_FLOAT_EQ(33, toInterpolableNumber(baseList->get(2))->value()); }
SVGPropertyBase* SVGPointListInterpolationType::appliedSVGValue( const InterpolableValue& interpolableValue, const NonInterpolableValue*) const { SVGPointList* result = SVGPointList::create(); const InterpolableList& list = toInterpolableList(interpolableValue); DCHECK_EQ(list.length() % 2, 0U); for (size_t i = 0; i < list.length(); i += 2) { FloatPoint point = FloatPoint(toInterpolableNumber(list.get(i))->value(), toInterpolableNumber(list.get(i + 1))->value()); result->append(SVGPoint::create(point)); } return result; }
double consumeInterpolableCoordinateAxis(const InterpolableValue* number, bool isAbsolute, double& currentValue) { double previousValue = currentValue; currentValue = toInterpolableNumber(number)->value(); return isAbsolute ? currentValue : currentValue - previousValue; }
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 CSSBorderImageLengthBoxInterpolationType::apply( const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const { const SideNumbers& sideNumbers = toCSSBorderImageLengthBoxNonInterpolableValue(nonInterpolableValue) ->sideNumbers(); const Vector<RefPtr<NonInterpolableValue>>& nonInterpolableValues = toCSSBorderImageLengthBoxNonInterpolableValue(nonInterpolableValue) ->sideNonInterpolableValues(); const InterpolableList& list = toInterpolableList(interpolableValue); const auto& convertSide = [&sideNumbers, &list, &environment, &nonInterpolableValues](size_t index) -> BorderImageLength { if (sideNumbers.isNumber[index]) return clampTo<double>(toInterpolableNumber(list.get(index))->value(), 0); return LengthInterpolationFunctions::createLength( *list.get(index), nonInterpolableValues[index].get(), environment.state().cssToLengthConversionData(), ValueRangeNonNegative); }; BorderImageLengthBox box(convertSide(SideTop), convertSide(SideRight), convertSide(SideBottom), convertSide(SideLeft)); BorderImageLengthBoxPropertyFunctions::setBorderImageLengthBox( cssProperty(), *environment.state().style(), box); }
PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGAngleInterpolationType::appliedSVGValue(const InterpolableValue& interpolableValue, const NonInterpolableValue*) const { double doubleValue = toInterpolableNumber(interpolableValue).value(); RefPtrWillBeRawPtr<SVGAngle> result = SVGAngle::create(); result->newValueSpecifiedUnits(SVGAngle::SVG_ANGLETYPE_DEG, doubleValue); return result.release(); }
PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGNumberListInterpolationType::appliedSVGValue(const InterpolableValue& interpolableValue, const NonInterpolableValue*) const { RefPtrWillBeRawPtr<SVGNumberList> result = SVGNumberList::create(); const InterpolableList& list = toInterpolableList(interpolableValue); for (size_t i = 0; i < list.length(); i++) result->append(SVGNumber::create(toInterpolableNumber(list.get(i))->value())); return result.release(); }
TEST_F(AnimationInterpolableValueTest, SimpleList) { OwnPtrWillBeRawPtr<InterpolableList> listA = InterpolableList::create(3); listA->set(0, InterpolableNumber::create(0)); listA->set(1, InterpolableNumber::create(42)); listA->set(2, InterpolableNumber::create(20.5)); OwnPtrWillBeRawPtr<InterpolableList> listB = InterpolableList::create(3); listB->set(0, InterpolableNumber::create(100)); listB->set(1, InterpolableNumber::create(-200)); listB->set(2, InterpolableNumber::create(300)); RefPtrWillBeRawPtr<Interpolation> i = interpolateLists(listA.release(), listB.release(), 0.3); InterpolableList* outList = toInterpolableList(interpolationValue(*i.get())); EXPECT_FLOAT_EQ(30, toInterpolableNumber(outList->get(0))->value()); EXPECT_FLOAT_EQ(-30.6f, toInterpolableNumber(outList->get(1))->value()); EXPECT_FLOAT_EQ(104.35f, toInterpolableNumber(outList->get(2))->value()); }
PassRefPtrWillBeRawPtr<CSSValue> DoubleStyleInterpolation::interpolableValueToDouble(const InterpolableValue* value, bool isNumber, InterpolationRange clamp) { ASSERT(value->isNumber()); double doubleValue = clampToRange(toInterpolableNumber(value)->value(), clamp); if (isNumber) return CSSPrimitiveValue::create(doubleValue, CSSPrimitiveValue::UnitType::Number); return CSSPrimitiveValue::create(doubleValue, CSSPrimitiveValue::UnitType::Degrees); }
PassRefPtrWillBeRawPtr<CSSValue> DoubleStyleInterpolation::interpolableValueToDouble(InterpolableValue* value, ClampRange clamp) { ASSERT(value->isNumber()); double doubleValue = toInterpolableNumber(value)->value(); if (clamp == ClampOpacity) { doubleValue = clampTo<float>(doubleValue, 0, nextafterf(1, 0)); } return CSSPrimitiveValue::create(doubleValue, CSSPrimitiveValue::CSS_NUMBER); }
PassOwnPtrWillBeRawPtr<InterpolableValue> InterpolableNumber::interpolate(const InterpolableValue &to, const double progress) const { const InterpolableNumber* toNumber = toInterpolableNumber(&to); if (!progress) return create(m_value); if (progress == 1) return create(toNumber->m_value); return create(m_value * (1 - progress) + toNumber->m_value * progress); }
PathSegmentData consumeInterpolableArc(const InterpolableValue& value, SVGPathSegType segType, PathCoordinates& coordinates) { const InterpolableList& list = toInterpolableList(value); bool isAbsolute = isAbsolutePathSegType(segType); PathSegmentData segment; segment.command = segType; segment.targetPoint.setX(consumeInterpolableCoordinateAxis( list.get(0), isAbsolute, coordinates.currentX)); segment.targetPoint.setY(consumeInterpolableCoordinateAxis( list.get(1), isAbsolute, coordinates.currentY)); segment.arcRadii().setX(toInterpolableNumber(list.get(2))->value()); segment.arcRadii().setY(toInterpolableNumber(list.get(3))->value()); segment.setArcAngle(toInterpolableNumber(list.get(4))->value()); segment.arcLarge = toInterpolableBool(list.get(5))->value(); segment.arcSweep = toInterpolableBool(list.get(6))->value(); return segment; }
PassRefPtrWillBeRawPtr<CSSPrimitiveValue> ColorStyleInterpolation::interpolableValueToColor(const InterpolableValue& value) { ASSERT(value.isList()); const InterpolableList* list = toInterpolableList(&value); double alpha = toInterpolableNumber(list->get(3))->value(); if (!alpha) return CSSPrimitiveValue::createColor(Color::transparent); // Clamping is inside makeRGBA. unsigned rgba = makeRGBA( round(toInterpolableNumber(list->get(0))->value() / alpha), round(toInterpolableNumber(list->get(1))->value() / alpha), round(toInterpolableNumber(list->get(2))->value() / alpha), round(alpha)); return CSSPrimitiveValue::createColor(rgba); }
PassRefPtrWillBeRawPtr<CSSValue> DoubleStyleInterpolation::interpolableValueToMotionRotation(InterpolableValue* value, bool flag) { RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); if (flag) list->append(CSSPrimitiveValue::createIdentifier(CSSValueAuto)); ASSERT(value->isNumber()); list->append(CSSPrimitiveValue::create(toInterpolableNumber(value)->value(), CSSPrimitiveValue::UnitType::Degrees)); return list.release(); }
static bool isPixelsOrPercentOnly(const InterpolableList& values) { for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { if (i == CSSPrimitiveValue::UnitTypePixels || i == CSSPrimitiveValue::UnitTypePercentage) continue; if (toInterpolableNumber(values.get(i))->value()) return false; } return true; }
SVGPropertyBase* SVGNumberListInterpolationType::appliedSVGValue( const InterpolableValue& interpolableValue, const NonInterpolableValue*) const { SVGNumberList* result = SVGNumberList::create(); const InterpolableList& list = toInterpolableList(interpolableValue); for (size_t i = 0; i < list.length(); i++) result->append( SVGNumber::create(toInterpolableNumber(list.get(i))->value())); return result; }
void CSSTransformInterpolationType::apply( const InterpolableValue& interpolableValue, const NonInterpolableValue* untypedNonInterpolableValue, InterpolationEnvironment& environment) const { double progress = toInterpolableNumber(interpolableValue).value(); const CSSTransformNonInterpolableValue& nonInterpolableValue = toCSSTransformNonInterpolableValue(*untypedNonInterpolableValue); environment.state().style()->setTransform( nonInterpolableValue.getInterpolatedTransform(progress)); }
void CSSRotateInterpolationType::apply( const InterpolableValue& interpolableValue, const NonInterpolableValue* untypedNonInterpolableValue, InterpolationEnvironment& environment) const { double progress = toInterpolableNumber(interpolableValue).value(); const CSSRotateNonInterpolableValue& nonInterpolableValue = toCSSRotateNonInterpolableValue(*untypedNonInterpolableValue); Rotation rotation = nonInterpolableValue.slerpedRotation(progress); environment.state().style()->setRotate( RotateTransformOperation::create(rotation, TransformOperation::Rotate3D)); }
TEST_F(AnimationDoubleStyleInterpolationTest, Clamping) { RefPtrWillBeRawPtr<Interpolation> interpolableDouble = DoubleStyleInterpolation::create( *CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_NUMBER), *CSSPrimitiveValue::create(0.6, CSSPrimitiveValue::CSS_NUMBER), CSSPropertyLineHeight, CSSPrimitiveValue::CSS_NUMBER, RangeAll); interpolableDouble->interpolate(0, 0.4); // progVal = start*(1-prog) + end*prog EXPECT_EQ(0.24, toInterpolableNumber(getCachedValue(*interpolableDouble))->value()); }
static PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> createCalcExpression(const InterpolableList& values, bool hasPercentage) { RefPtrWillBeRawPtr<CSSCalcExpressionNode> result = nullptr; for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { double value = toInterpolableNumber(values.get(i))->value(); if (value || (i == CSSPrimitiveValue::UnitTypePercentage && hasPercentage)) { RefPtrWillBeRawPtr<CSSCalcExpressionNode> node = CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(value, toUnitType(i))); result = result ? CSSCalcValue::createExpressionNode(result.release(), node.release(), CalcAdd) : node.release(); } } ASSERT(result); return result.release(); }
TEST_F(AnimationInterpolableValueTest, NestedList) { OwnPtrWillBeRawPtr<InterpolableList> listA = InterpolableList::create(3); listA->set(0, InterpolableNumber::create(0)); OwnPtrWillBeRawPtr<InterpolableList> subListA = InterpolableList::create(1); subListA->set(0, InterpolableNumber::create(100)); listA->set(1, subListA.release()); listA->set(2, InterpolableBool::create(false)); OwnPtrWillBeRawPtr<InterpolableList> listB = InterpolableList::create(3); listB->set(0, InterpolableNumber::create(100)); OwnPtrWillBeRawPtr<InterpolableList> subListB = InterpolableList::create(1); subListB->set(0, InterpolableNumber::create(50)); listB->set(1, subListB.release()); listB->set(2, InterpolableBool::create(true)); RefPtrWillBeRawPtr<Interpolation> i = interpolateLists(listA.release(), listB.release(), 0.5); InterpolableList* outList = toInterpolableList(interpolationValue(*i.get())); EXPECT_FLOAT_EQ(50, toInterpolableNumber(outList->get(0))->value()); EXPECT_FLOAT_EQ(75, toInterpolableNumber(toInterpolableList(outList->get(1))->get(0))->value()); EXPECT_TRUE(toInterpolableBool(outList->get(2))->value()); }