Chromium Code Reviews| Index: Source/core/animation/LengthInterpolationType.cpp |
| diff --git a/Source/core/animation/LengthInterpolationType.cpp b/Source/core/animation/LengthInterpolationType.cpp |
| index 668d312696f0092f8317479cc2cb371bbe120032..de0e8521ad2f184659df95f1d0f06bf6af47c9ba 100644 |
| --- a/Source/core/animation/LengthInterpolationType.cpp |
| +++ b/Source/core/animation/LengthInterpolationType.cpp |
| @@ -6,30 +6,44 @@ |
| #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 { |
| +class HasPercentage : public NonInterpolableValue { |
|
dstockwell
2015/08/31 06:44:26
I was going to suggest LengthHasPercentage but I g
alancutter (OOO until 2018)
2015/09/01 00:26:00
Added comment.
|
| +public: |
| + ~HasPercentage() override { ASSERT_NOT_REACHED(); } |
| + static PassRefPtrWillBeRawPtr<HasPercentage> get() |
| + { |
| + DEFINE_STATIC_REF_WILL_BE_PERSISTENT(HasPercentage, singleton, adoptRefWillBeNoop(new HasPercentage())); |
| + ASSERT(singleton); |
| + return singleton; |
| + } |
| + DEFINE_INLINE_VIRTUAL_TRACE() { NonInterpolableValue::trace(visitor); } |
| + DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); |
| + |
| +private: |
| + HasPercentage() { } |
| +}; |
| + |
| +DEFINE_NON_INTERPOLABLE_VALUE_TYPE(HasPercentage); |
| +DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(HasPercentage); |
| + |
| LengthInterpolationType::LengthInterpolationType(CSSPropertyID property) |
| : InterpolationType(property) |
| , m_valueRange(LengthPropertyFunctions::valueRange(property)) |
| { } |
| -static PassOwnPtrWillBeRawPtr<InterpolableList> createNeutralValue() |
| +static PassOwnPtrWillBeRawPtr<InterpolableList> createNeutralInterpolableValue() |
| { |
| - OwnPtrWillBeRawPtr<InterpolableList> listOfValuesAndTypes = InterpolableList::create(2); |
| const size_t length = CSSPrimitiveValue::LengthUnitTypeCount; |
| - OwnPtrWillBeRawPtr<InterpolableList> listOfValues = InterpolableList::create(length); |
| - // TODO(alancutter): Use a NonInterpolableValue to represent the list of types. |
| - OwnPtrWillBeRawPtr<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(); |
| + OwnPtrWillBeRawPtr<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 +57,11 @@ PassOwnPtrWillBeRawPtr<InterpolationValue> LengthInterpolationType::maybeConvert |
| return nullptr; |
| PixelsAndPercent pixelsAndPercent = length.pixelsAndPercent(); |
| - OwnPtrWillBeRawPtr<InterpolableList> valuesAndTypes = createNeutralValue(); |
| + OwnPtrWillBeRawPtr<InterpolableList> values = createNeutralInterpolableValue(); |
| + values->set(CSSPrimitiveValue::UnitTypePixels, InterpolableNumber::create(pixelsAndPercent.pixels / zoom)); |
| + values->set(CSSPrimitiveValue::UnitTypePercentage, InterpolableNumber::create(pixelsAndPercent.percent)); |
| - InterpolableList& values = toInterpolableList(*valuesAndTypes->get(0)); |
| - 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(), length.hasPercent() ? HasPercentage::get() : nullptr); |
| } |
| class ParentLengthChecker : public InterpolationType::ConversionChecker { |
| @@ -88,7 +96,7 @@ private: |
| PassOwnPtrWillBeRawPtr<InterpolationValue> LengthInterpolationType::maybeConvertNeutral() const |
| { |
| - return InterpolationValue::create(*this, createNeutralValue()); |
| + return InterpolationValue::create(*this, createNeutralInterpolableValue()); |
| } |
| PassOwnPtrWillBeRawPtr<InterpolationValue> LengthInterpolationType::maybeConvertInitial() const |
| @@ -117,38 +125,32 @@ PassOwnPtrWillBeRawPtr<InterpolationValue> LengthInterpolationType::maybeConvert |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| - OwnPtrWillBeRawPtr<InterpolableList> listOfValuesAndTypes = InterpolableList::create(2); |
| - OwnPtrWillBeRawPtr<InterpolableList> listOfValues = InterpolableList::create(CSSPrimitiveValue::LengthUnitTypeCount); |
| - OwnPtrWillBeRawPtr<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()); |
| + OwnPtrWillBeRawPtr<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(), hasPercentage ? HasPercentage::get() : nullptr); |
| } |
| PassOwnPtrWillBeRawPtr<InterpolationValue> LengthInterpolationType::maybeConvertUnderlyingValue(const StyleResolverState& state) const |
| @@ -159,12 +161,101 @@ PassOwnPtrWillBeRawPtr<InterpolationValue> LengthInterpolationType::maybeConvert |
| return maybeConvertLength(underlyingLength, effectiveZoom(*state.style())); |
| } |
| -void LengthInterpolationType::apply(const InterpolableValue& interpolableValue, const NonInterpolableValue*, StyleResolverState& state) const |
| +PassRefPtrWillBeRawPtr<NonInterpolableValue> LengthInterpolationType::mergeNonInterpolableValues(const NonInterpolableValue* a, const NonInterpolableValue* b) const |
| +{ |
| + return (toHasPercentage(a) || toHasPercentage(b)) ? HasPercentage::get() : nullptr; |
| +} |
| + |
| +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; |
| +} |
| + |
| +static double clampToRange(double x, ValueRange range) |
|
dstockwell
2015/08/31 06:44:26
Move this alongside ValueRange.
alancutter (OOO until 2018)
2015/09/01 00:26:00
It's probably better if this is done in as separat
|
| { |
| - // 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); |
| + 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; |
| + 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 = toHasPercentage(nonInterpolableValue); |
|
dstockwell
2015/08/31 06:44:26
On further thoughts, lets rename HasPercentage to
alancutter (OOO until 2018)
2015/09/01 00:26:00
Done, changed get() to create(bool hasPercentage)
|
| + if (isPixelsOrPercentOnly(values)) { |
| + Length length = createLength(values, hasPercentage, m_valueRange, effectiveZoom(*state.style())); |
| + if (LengthPropertyFunctions::setLength(m_property, *state.style(), length)) { |
| +#if ENABLE(ASSERT) |
| + RefPtrWillBeRawPtr<AnimatableValue> before = CSSAnimatableValueFactory::create(m_property, *state.style()); |
| + StyleBuilder::applyProperty(m_property, state, createCSSValue(values, hasPercentage, m_valueRange).get()); |
| + RefPtrWillBeRawPtr<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 |