1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "config.h" 6 #include "core/animation/interpolation/LengthStyleInterpolation.h" 7 8 #include "core/css/CSSCalculationValue.h" 9 #include "core/css/resolver/StyleBuilder.h" 10 11 namespace WebCore { 12 13 bool LengthStyleInterpolation::canCreateFrom(const CSSValue& value) 14 { 15 if (value.isPrimitiveValue()) { 16 const CSSPrimitiveValue& primitiveValue = WebCore::toCSSPrimitiveValue(value); 17 if (primitiveValue.cssCalcValue()) 18 return true; 19 20 CSSPrimitiveValue::LengthUnitType type; 21 // Only returns true if the type is a primitive length unit. 22 return CSSPrimitiveValue::unitTypeToLengthUnitType(primitiveValue.primitiveType(), type); 23 } 24 return value.isCalcValue(); 25 } 26 27 PassOwnPtrWillBeRawPtr<InterpolableValue> LengthStyleInterpolation::lengthToInterpolableValue(CSSValue* value) 28 { 29 OwnPtrWillBeRawPtr<InterpolableList> result = InterpolableList::create(CSSPrimitiveValue::LengthUnitTypeCount); 30 CSSPrimitiveValue* primitive = toCSSPrimitiveValue(value); 31 32 CSSLengthArray array; 33 for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) 34 array.append(0); 35 primitive->accumulateLengthArray(array); 36 37 for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) 38 result->set(i, InterpolableNumber::create(array.at(i))); 39 40 return result.release(); 41 } 42 43 namespace { 44 45 static CSSPrimitiveValue::UnitType toUnitType(int lengthUnitType) 46 { 47 return static_cast<CSSPrimitiveValue::UnitType>(CSSPrimitiveValue::lengthUnitTypeToUnitType(static_cast<CSSPrimitiveValue::LengthUnitType>(lengthUnitType))); 48 } 49 50 static PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> constructCalcExpression(PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> previous, InterpolableList* list, size_t position) 51 { 52 while (position != CSSPrimitiveValue::LengthUnitTypeCount) { 53 const InterpolableNumber *subValue = toInterpolableNumber(list->get(position)); 54 if (subValue->value()) { 55 RefPtrWillBeRawPtr<CSSCalcExpressionNode> next; 56 if (previous) 57 next = CSSCalcValue::createExpressionNode(previous, CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(subValue->value(), toUnitType(position))), CalcAdd); 58 else 59 next = CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(subValue->value(), toUnitType(position))); 60 return constructCalcExpression(next, list, position + 1); 61 } 62 position++; 63 } 64 return previous; 65 } 66 67 } 68 69 PassRefPtrWillBeRawPtr<CSSValue> LengthStyleInterpolation::interpolableValueToLength(InterpolableValue* value, ValueRange range) 70 { 71 InterpolableList* listValue = toInterpolableList(value); 72 unsigned unitCount = 0; 73 for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { 74 const InterpolableNumber* subValue = toInterpolableNumber(listValue->get(i)); 75 if (subValue->value()) { 76 unitCount++; 77 } 78 } 79 80 switch (unitCount) { 81 case 0: 82 return CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX); 83 case 1: 84 for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { 85 const InterpolableNumber* subValue = toInterpolableNumber(listValue->get(i)); 86 double value = subValue->value(); 87 if (value) { 88 if (range == ValueRangeNonNegative && value < 0) 89 value = 0; 90 return CSSPrimitiveValue::create(value, toUnitType(i)); 91 } 92 } 93 ASSERT_NOT_REACHED(); 94 default: 95 return CSSPrimitiveValue::create(CSSCalcValue::create(constructCalcExpression(nullptr, listValue, 0), range)); 96 } 97 } 98 99 void LengthStyleInterpolation::apply(StyleResolverState& state) const 100 { 101 StyleBuilder::applyProperty(m_id, state, interpolableValueToLength(m_cachedValue.get(), m_range).get()); 102 } 103 104 void LengthStyleInterpolation::trace(Visitor* visitor) 105 { 106 StyleInterpolation::trace(visitor); 107 } 108 109 } 110