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