| Index: Source/core/animation/LengthInterpolationType.cpp
|
| diff --git a/Source/core/animation/LengthInterpolationType.cpp b/Source/core/animation/LengthInterpolationType.cpp
|
| index a872f1de65dbf55429c1c549c8cc90fd829c380e..21214df6aaa246417095aa397b9a21fc56ef643f 100644
|
| --- a/Source/core/animation/LengthInterpolationType.cpp
|
| +++ b/Source/core/animation/LengthInterpolationType.cpp
|
| @@ -6,30 +6,55 @@
|
| #include "core/animation/LengthInterpolationType.h"
|
|
|
| #include "core/animation/LengthPropertyFunctions.h"
|
| -#include "core/animation/LengthStyleInterpolation.h"
|
| +#include "core/animation/css/CSSAnimatableValueFactory.h"
|
| +#include "core/css/CSSCalculationValue.h"
|
| +#include "core/css/resolver/StyleBuilder.h"
|
| #include "core/css/resolver/StyleResolverState.h"
|
|
|
| namespace blink {
|
|
|
| +// This class is implemented as a singleton whose instance represents the presence of percentages being used in a Length value
|
| +// while nullptr represents the absence of any percentages.
|
| +class LengthNonInterpolableValue : public NonInterpolableValue {
|
| +public:
|
| + ~LengthNonInterpolableValue() override { ASSERT_NOT_REACHED(); }
|
| + static PassRefPtr<LengthNonInterpolableValue> create(bool hasPercentage)
|
| + {
|
| + DEFINE_STATIC_REF_WILL_BE_PERSISTENT(LengthNonInterpolableValue, singleton, adoptRef(new LengthNonInterpolableValue()));
|
| + ASSERT(singleton);
|
| + return hasPercentage ? singleton : nullptr;
|
| + }
|
| + static PassRefPtr<LengthNonInterpolableValue> merge(const NonInterpolableValue* a, const NonInterpolableValue* b)
|
| + {
|
| + return create(hasPercentage(a) || hasPercentage(b));
|
| + }
|
| + static bool hasPercentage(const NonInterpolableValue* nonInterpolableValue)
|
| + {
|
| + ASSERT(!nonInterpolableValue || nonInterpolableValue->type() == LengthNonInterpolableValue::staticType);
|
| + return static_cast<bool>(nonInterpolableValue);
|
| + }
|
| + DEFINE_INLINE_VIRTUAL_TRACE() { NonInterpolableValue::trace(visitor); }
|
| + DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
|
| +
|
| +private:
|
| + LengthNonInterpolableValue() { }
|
| +};
|
| +
|
| +DEFINE_NON_INTERPOLABLE_VALUE_TYPE(LengthNonInterpolableValue);
|
| +DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(LengthNonInterpolableValue);
|
| +
|
| LengthInterpolationType::LengthInterpolationType(CSSPropertyID property)
|
| : InterpolationType(property)
|
| , m_valueRange(LengthPropertyFunctions::valueRange(property))
|
| { }
|
|
|
| -static PassOwnPtr<InterpolableList> createNeutralValue()
|
| +static PassOwnPtr<InterpolableList> createNeutralInterpolableValue()
|
| {
|
| - OwnPtr<InterpolableList> listOfValuesAndTypes = InterpolableList::create(2);
|
| const size_t length = CSSPrimitiveValue::LengthUnitTypeCount;
|
| - OwnPtr<InterpolableList> listOfValues = InterpolableList::create(length);
|
| - // TODO(alancutter): Use a NonInterpolableValue to represent the list of types.
|
| - OwnPtr<InterpolableList> listOfTypes = InterpolableList::create(length);
|
| - for (size_t i = 0; i < length; i++) {
|
| - listOfValues->set(i, InterpolableNumber::create(0));
|
| - listOfTypes->set(i, InterpolableNumber::create(0));
|
| - }
|
| - listOfValuesAndTypes->set(0, listOfValues.release());
|
| - listOfValuesAndTypes->set(1, listOfTypes.release());
|
| - return listOfValuesAndTypes.release();
|
| + OwnPtr<InterpolableList> values = InterpolableList::create(length);
|
| + for (size_t i = 0; i < length; i++)
|
| + values->set(i, InterpolableNumber::create(0));
|
| + return values.release();
|
| }
|
|
|
| float LengthInterpolationType::effectiveZoom(const ComputedStyle& style) const
|
| @@ -43,17 +68,11 @@ PassOwnPtr<InterpolationValue> LengthInterpolationType::maybeConvertLength(const
|
| return nullptr;
|
|
|
| PixelsAndPercent pixelsAndPercent = length.pixelsAndPercent();
|
| - OwnPtr<InterpolableList> valuesAndTypes = createNeutralValue();
|
| -
|
| - InterpolableList& values = toInterpolableList(*valuesAndTypes->get(0));
|
| - values.set(CSSPrimitiveValue::UnitTypePixels, InterpolableNumber::create(pixelsAndPercent.pixels / zoom));
|
| - values.set(CSSPrimitiveValue::UnitTypePercentage, InterpolableNumber::create(pixelsAndPercent.percent));
|
| + OwnPtr<InterpolableList> values = createNeutralInterpolableValue();
|
| + values->set(CSSPrimitiveValue::UnitTypePixels, InterpolableNumber::create(pixelsAndPercent.pixels / zoom));
|
| + values->set(CSSPrimitiveValue::UnitTypePercentage, InterpolableNumber::create(pixelsAndPercent.percent));
|
|
|
| - InterpolableList& types = toInterpolableList(*valuesAndTypes->get(1));
|
| - types.set(CSSPrimitiveValue::UnitTypePixels, InterpolableNumber::create(pixelsAndPercent.pixels != 0));
|
| - types.set(CSSPrimitiveValue::UnitTypePercentage, InterpolableNumber::create(length.hasPercent()));
|
| -
|
| - return InterpolationValue::create(*this, valuesAndTypes.release());
|
| + return InterpolationValue::create(*this, values.release(), LengthNonInterpolableValue::create(length.hasPercent()));
|
| }
|
|
|
| class ParentLengthChecker : public InterpolationType::ConversionChecker {
|
| @@ -83,7 +102,7 @@ private:
|
|
|
| PassOwnPtr<InterpolationValue> LengthInterpolationType::maybeConvertNeutral() const
|
| {
|
| - return InterpolationValue::create(*this, createNeutralValue());
|
| + return InterpolationValue::create(*this, createNeutralInterpolableValue());
|
| }
|
|
|
| PassOwnPtr<InterpolationValue> LengthInterpolationType::maybeConvertInitial() const
|
| @@ -112,38 +131,31 @@ PassOwnPtr<InterpolationValue> LengthInterpolationType::maybeConvertValue(const
|
|
|
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value);
|
|
|
| - OwnPtr<InterpolableList> listOfValuesAndTypes = InterpolableList::create(2);
|
| - OwnPtr<InterpolableList> listOfValues = InterpolableList::create(CSSPrimitiveValue::LengthUnitTypeCount);
|
| - OwnPtr<InterpolableList> listOfTypes = InterpolableList::create(CSSPrimitiveValue::LengthUnitTypeCount);
|
| -
|
| - CSSLengthArray arrayOfValues;
|
| - CSSLengthTypeArray arrayOfTypes;
|
| + CSSLengthArray valueArray;
|
| for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++)
|
| - arrayOfValues.append(0);
|
| - arrayOfTypes.ensureSize(CSSPrimitiveValue::LengthUnitTypeCount);
|
| + valueArray.append(0);
|
| + bool hasPercentage = false;
|
|
|
| if (primitiveValue.isValueID()) {
|
| CSSValueID valueID = primitiveValue.getValueID();
|
| double pixels;
|
| if (!LengthPropertyFunctions::getPixelsForKeyword(m_property, valueID, pixels))
|
| return nullptr;
|
| - arrayOfTypes.set(CSSPrimitiveValue::UnitTypePixels);
|
| - arrayOfValues[CSSPrimitiveValue::UnitTypePixels] = pixels;
|
| + valueArray[CSSPrimitiveValue::UnitTypePixels] = pixels;
|
| } else {
|
| if (!primitiveValue.isLength() && !primitiveValue.isPercentage() && !primitiveValue.isCalculatedPercentageWithLength())
|
| return nullptr;
|
| - primitiveValue.accumulateLengthArray(arrayOfValues, arrayOfTypes);
|
| + CSSLengthTypeArray hasType;
|
| + hasType.ensureSize(CSSPrimitiveValue::LengthUnitTypeCount);
|
| + primitiveValue.accumulateLengthArray(valueArray, hasType);
|
| + hasPercentage = hasType.get(CSSPrimitiveValue::UnitTypePercentage);
|
| }
|
|
|
| - for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) {
|
| - listOfValues->set(i, InterpolableNumber::create(arrayOfValues.at(i)));
|
| - listOfTypes->set(i, InterpolableNumber::create(arrayOfTypes.get(i)));
|
| - }
|
| -
|
| - listOfValuesAndTypes->set(0, listOfValues.release());
|
| - listOfValuesAndTypes->set(1, listOfTypes.release());
|
| + OwnPtr<InterpolableList> values = InterpolableList::create(CSSPrimitiveValue::LengthUnitTypeCount);
|
| + for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++)
|
| + values->set(i, InterpolableNumber::create(valueArray.at(i)));
|
|
|
| - return InterpolationValue::create(*this, listOfValuesAndTypes.release());
|
| + return InterpolationValue::create(*this, values.release(), LengthNonInterpolableValue::create(hasPercentage));
|
| }
|
|
|
| PassOwnPtr<InterpolationValue> LengthInterpolationType::maybeConvertUnderlyingValue(const StyleResolverState& state) const
|
| @@ -154,12 +166,113 @@ PassOwnPtr<InterpolationValue> LengthInterpolationType::maybeConvertUnderlyingVa
|
| return maybeConvertLength(underlyingLength, effectiveZoom(*state.style()));
|
| }
|
|
|
| -void LengthInterpolationType::apply(const InterpolableValue& interpolableValue, const NonInterpolableValue*, StyleResolverState& state) const
|
| +PassOwnPtr<PairwisePrimitiveInterpolation> LengthInterpolationType::mergeSingleConversions(InterpolationValue& startValue, InterpolationValue& endValue) const
|
| +{
|
| + return PairwisePrimitiveInterpolation::create(*this,
|
| + startValue.mutableComponent().interpolableValue.release(),
|
| + endValue.mutableComponent().interpolableValue.release(),
|
| + LengthNonInterpolableValue::merge(startValue.nonInterpolableValue(), endValue.nonInterpolableValue()));
|
| +}
|
| +
|
| +void LengthInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const
|
| {
|
| - // TODO(alancutter): Make all length interpolation functions operate on ValueRanges instead of InterpolationRanges.
|
| - InterpolationRange range = m_valueRange == ValueRangeNonNegative ? RangeNonNegative : RangeAll;
|
| - // TODO(alancutter): Set arbitrary property Lengths on ComputedStyle without using cross compilation unit member function getters (Windows runtime doesn't like it).
|
| - LengthStyleInterpolation::applyInterpolableValue(m_property, interpolableValue, range, state);
|
| + InterpolationComponentValue& underlyingComponent = underlyingValue.mutableComponent();
|
| + underlyingComponent.interpolableValue->scaleAndAdd(underlyingFraction, value.interpolableValue());
|
| + underlyingComponent.nonInterpolableValue = LengthNonInterpolableValue::merge(underlyingValue->nonInterpolableValue(), value.nonInterpolableValue());
|
| +}
|
| +
|
| +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;
|
| +}
|
| +
|
| +// TODO(alancutter): Move this to Length.h.
|
| +static double clampToRange(double x, ValueRange range)
|
| +{
|
| + return (range == ValueRangeNonNegative && x < 0) ? 0 : x;
|
| +}
|
| +
|
| +static Length createLength(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();
|
| + ASSERT(hasPercentage || percentage == 0);
|
| +
|
| + if (pixels && hasPercentage)
|
| + return Length(CalculationValue::create(PixelsAndPercent(pixels, percentage), range));
|
| + if (hasPercentage)
|
| + return Length(clampToRange(percentage, range), Percent);
|
| + return Length(CSSPrimitiveValue::clampToCSSLengthRange(clampToRange(pixels, range)), Fixed);
|
| +}
|
| +
|
| +static CSSPrimitiveValue::UnitType toUnitType(int lengthUnitType)
|
| +{
|
| + return static_cast<CSSPrimitiveValue::UnitType>(CSSPrimitiveValue::lengthUnitTypeToUnitType(static_cast<CSSPrimitiveValue::LengthUnitType>(lengthUnitType)));
|
| +}
|
| +
|
| +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();
|
| +}
|
| +
|
| +static PassRefPtrWillBeRawPtr<CSSValue> createCSSValue(const InterpolableList& values, bool hasPercentage, ValueRange range)
|
| +{
|
| + RefPtrWillBeRawPtr<CSSPrimitiveValue> result;
|
| + size_t firstUnitIndex = CSSPrimitiveValue::LengthUnitTypeCount;
|
| + size_t unitTypeCount = 0;
|
| + for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) {
|
| + if ((hasPercentage && i == CSSPrimitiveValue::UnitTypePercentage) || toInterpolableNumber(values.get(i))->value()) {
|
| + unitTypeCount++;
|
| + if (unitTypeCount == 1)
|
| + firstUnitIndex = i;
|
| + }
|
| + }
|
| + switch (unitTypeCount) {
|
| + case 0:
|
| + return CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Pixels);
|
| + case 1: {
|
| + double value = clampToRange(toInterpolableNumber(values.get(firstUnitIndex))->value(), range);
|
| + return CSSPrimitiveValue::create(value, toUnitType(firstUnitIndex));
|
| + }
|
| + default:
|
| + return CSSPrimitiveValue::create(CSSCalcValue::create(createCalcExpression(values, hasPercentage), range));
|
| + }
|
| +}
|
| +
|
| +void LengthInterpolationType::apply(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, StyleResolverState& state) const
|
| +{
|
| + const InterpolableList& values = toInterpolableList(interpolableValue);
|
| + bool hasPercentage = LengthNonInterpolableValue::hasPercentage(nonInterpolableValue);
|
| + if (isPixelsOrPercentOnly(values)) {
|
| + Length length = createLength(values, hasPercentage, m_valueRange, effectiveZoom(*state.style()));
|
| + if (LengthPropertyFunctions::setLength(m_property, *state.style(), length)) {
|
| +#if ENABLE(ASSERT)
|
| + // Assert that setting the length on ComputedStyle directly is identical to the AnimatableValue code path.
|
| + RefPtr<AnimatableValue> before = CSSAnimatableValueFactory::create(m_property, *state.style());
|
| + StyleBuilder::applyProperty(m_property, state, createCSSValue(values, hasPercentage, m_valueRange).get());
|
| + RefPtr<AnimatableValue> after = CSSAnimatableValueFactory::create(m_property, *state.style());
|
| + ASSERT(before->equals(*after));
|
| +#endif
|
| + return;
|
| + }
|
| + }
|
| + StyleBuilder::applyProperty(m_property, state, createCSSValue(values, hasPercentage, m_valueRange).get());
|
| }
|
|
|
| } // namespace blink
|
|
|