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/LengthStyleInterpolation.h" 7 8#include "core/css/CSSCalculationValue.h" 9#include "core/css/resolver/StyleBuilder.h" 10 11namespace blink { 12 13bool LengthStyleInterpolation::canCreateFrom(const CSSValue& value) 14{ 15 if (value.isPrimitiveValue()) { 16 const CSSPrimitiveValue& primitiveValue = blink::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 27PassOwnPtrWillBeRawPtr<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 43namespace { 44 45static CSSPrimitiveValue::UnitType toUnitType(int lengthUnitType) 46{ 47 return static_cast<CSSPrimitiveValue::UnitType>(CSSPrimitiveValue::lengthUnitTypeToUnitType(static_cast<CSSPrimitiveValue::LengthUnitType>(lengthUnitType))); 48} 49 50static 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 69PassRefPtrWillBeRawPtr<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 99void LengthStyleInterpolation::apply(StyleResolverState& state) const 100{ 101 StyleBuilder::applyProperty(m_id, state, interpolableValueToLength(m_cachedValue.get(), m_range).get()); 102} 103 104void LengthStyleInterpolation::trace(Visitor* visitor) 105{ 106 StyleInterpolation::trace(visitor); 107} 108 109} 110