• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "core/animation/AnimatableLength.h"
33 
34 #include "core/css/CSSPrimitiveValueMappings.h"
35 #include "platform/CalculationValue.h"
36 #include "platform/animation/AnimationUtilities.h"
37 
38 namespace WebCore {
39 
create(CSSValue * value)40 PassRefPtr<AnimatableLength> AnimatableLength::create(CSSValue* value)
41 {
42     ASSERT(canCreateFrom(value));
43     if (value->isPrimitiveValue()) {
44         CSSPrimitiveValue* primitiveValue = WebCore::toCSSPrimitiveValue(value);
45         const CSSCalcValue* calcValue = primitiveValue->cssCalcValue();
46         if (calcValue)
47             return create(calcValue->expressionNode(), primitiveValue);
48         NumberUnitType unitType;
49         bool isPrimitiveLength = primitiveUnitToNumberType(primitiveValue->primitiveType(), unitType);
50         ASSERT_UNUSED(isPrimitiveLength, isPrimitiveLength);
51         const double scale = CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(primitiveValue->primitiveType());
52         return create(primitiveValue->getDoubleValue() * scale, unitType, primitiveValue);
53     }
54 
55     if (value->isCalcValue())
56         return create(toCSSCalcValue(value)->expressionNode());
57 
58     ASSERT_NOT_REACHED();
59     return 0;
60 }
61 
canCreateFrom(const CSSValue * value)62 bool AnimatableLength::canCreateFrom(const CSSValue* value)
63 {
64     ASSERT(value);
65     if (value->isPrimitiveValue()) {
66         const CSSPrimitiveValue* primitiveValue = WebCore::toCSSPrimitiveValue(value);
67         if (primitiveValue->cssCalcValue())
68             return true;
69 
70         NumberUnitType unitType;
71         // Only returns true if the type is a primitive length unit.
72         return primitiveUnitToNumberType(primitiveValue->primitiveType(), unitType);
73     }
74     return value->isCalcValue();
75 }
76 
toCSSValue(NumberRange range) const77 PassRefPtr<CSSValue> AnimatableLength::toCSSValue(NumberRange range) const
78 {
79     return toCSSPrimitiveValue(range);
80 }
81 
toLength(const CSSToLengthConversionData & conversionData,NumberRange range) const82 Length AnimatableLength::toLength(const CSSToLengthConversionData& conversionData, NumberRange range) const
83 {
84     // Avoid creating a CSSValue in the common cases
85     if (m_unitType == UnitTypePixels)
86         return Length(clampedNumber(range) * conversionData.zoom(), Fixed);
87     if (m_unitType == UnitTypePercentage)
88         return Length(clampedNumber(range), Percent);
89 
90     return toCSSPrimitiveValue(range)->convertToLength<AnyConversion>(conversionData);
91 }
92 
interpolateTo(const AnimatableValue * value,double fraction) const93 PassRefPtr<AnimatableValue> AnimatableLength::interpolateTo(const AnimatableValue* value, double fraction) const
94 {
95     const AnimatableLength* length = toAnimatableLength(value);
96     NumberUnitType type = commonUnitType(length);
97     if (type != UnitTypeCalc)
98         return AnimatableLength::create(blend(m_number, length->m_number, fraction), type);
99 
100     // FIXME(crbug.com/168840): Support for viewport units in calc needs to be added before we can blend them with other units.
101     if (isViewportUnit() || length->isViewportUnit())
102         return defaultInterpolateTo(this, value, fraction);
103 
104     return AnimatableLength::create(scale(1 - fraction).get(), length->scale(fraction).get());
105 }
106 
addWith(const AnimatableValue * value) const107 PassRefPtr<AnimatableValue> AnimatableLength::addWith(const AnimatableValue* value) const
108 {
109     // Optimization for adding with 0.
110     if (isUnitlessZero())
111         return takeConstRef(value);
112 
113     const AnimatableLength* length = toAnimatableLength(value);
114     if (length->isUnitlessZero())
115         return takeConstRef(this);
116 
117     NumberUnitType type = commonUnitType(length);
118     if (type != UnitTypeCalc)
119         return AnimatableLength::create(m_number + length->m_number, type);
120 
121     return AnimatableLength::create(this, length);
122 }
123 
equalTo(const AnimatableValue * value) const124 bool AnimatableLength::equalTo(const AnimatableValue* value) const
125 {
126     const AnimatableLength* length = toAnimatableLength(value);
127     if (m_unitType != length->m_unitType)
128         return false;
129     if (isCalc())
130         return m_calcExpression == length->m_calcExpression || m_calcExpression->equals(*length->m_calcExpression);
131     return m_number == length->m_number;
132 }
133 
toCSSCalcExpressionNode() const134 PassRefPtr<CSSCalcExpressionNode> AnimatableLength::toCSSCalcExpressionNode() const
135 {
136     if (isCalc())
137         return m_calcExpression;
138     return CSSCalcValue::createExpressionNode(toCSSPrimitiveValue(AllValues), m_number == trunc(m_number));
139 }
140 
isCompatibleWithRange(const CSSPrimitiveValue * primitiveValue,NumberRange range)141 static bool isCompatibleWithRange(const CSSPrimitiveValue* primitiveValue, NumberRange range)
142 {
143     ASSERT(primitiveValue);
144     if (range == AllValues)
145         return true;
146     if (primitiveValue->isCalculated())
147         return primitiveValue->cssCalcValue()->permittedValueRange() == ValueRangeNonNegative;
148     return primitiveValue->getDoubleValue() >= 0;
149 }
150 
toCSSPrimitiveValue(NumberRange range) const151 PassRefPtr<CSSPrimitiveValue> AnimatableLength::toCSSPrimitiveValue(NumberRange range) const
152 {
153     if (!m_cachedCSSPrimitiveValue || !isCompatibleWithRange(m_cachedCSSPrimitiveValue.get(), range)) {
154         if (isCalc())
155             m_cachedCSSPrimitiveValue = CSSPrimitiveValue::create(CSSCalcValue::create(m_calcExpression, range == AllValues ? ValueRangeAll : ValueRangeNonNegative));
156         else
157             m_cachedCSSPrimitiveValue = CSSPrimitiveValue::create(clampedNumber(range), static_cast<CSSPrimitiveValue::UnitTypes>(numberTypeToPrimitiveUnit(m_unitType)));
158     }
159     return m_cachedCSSPrimitiveValue;
160 }
161 
scale(double factor) const162 PassRefPtr<AnimatableLength> AnimatableLength::scale(double factor) const
163 {
164     if (isCalc()) {
165         return AnimatableLength::create(CSSCalcValue::createExpressionNode(
166             m_calcExpression,
167             CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(factor, CSSPrimitiveValue::CSS_NUMBER)),
168             CalcMultiply));
169     }
170     return AnimatableLength::create(m_number * factor, m_unitType);
171 }
172 
primitiveUnitToNumberType(unsigned short primitiveUnit,NumberUnitType & numberType)173 bool AnimatableLength::primitiveUnitToNumberType(unsigned short primitiveUnit, NumberUnitType& numberType)
174 {
175     switch (primitiveUnit) {
176     case CSSPrimitiveValue::CSS_PX:
177     case CSSPrimitiveValue::CSS_CM:
178     case CSSPrimitiveValue::CSS_MM:
179     case CSSPrimitiveValue::CSS_IN:
180     case CSSPrimitiveValue::CSS_PT:
181     case CSSPrimitiveValue::CSS_PC:
182         numberType = UnitTypePixels;
183         return true;
184     case CSSPrimitiveValue::CSS_EMS:
185         numberType = UnitTypeFontSize;
186         return true;
187     case CSSPrimitiveValue::CSS_EXS:
188         numberType = UnitTypeFontXSize;
189         return true;
190     case CSSPrimitiveValue::CSS_REMS:
191         numberType = UnitTypeRootFontSize;
192         return true;
193     case CSSPrimitiveValue::CSS_PERCENTAGE:
194         numberType = UnitTypePercentage;
195         return true;
196     case CSSPrimitiveValue::CSS_VW:
197         numberType = UnitTypeViewportWidth;
198         return true;
199     case CSSPrimitiveValue::CSS_VH:
200         numberType = UnitTypeViewportHeight;
201         return true;
202     case CSSPrimitiveValue::CSS_VMIN:
203         numberType = UnitTypeViewportMin;
204         return true;
205     case CSSPrimitiveValue::CSS_VMAX:
206         numberType = UnitTypeViewportMax;
207         return true;
208     default:
209         return false;
210     }
211 }
212 
numberTypeToPrimitiveUnit(NumberUnitType numberType)213 unsigned short AnimatableLength::numberTypeToPrimitiveUnit(NumberUnitType numberType)
214 {
215     switch (numberType) {
216     case UnitTypePixels:
217         return CSSPrimitiveValue::CSS_PX;
218     case UnitTypeFontSize:
219         return CSSPrimitiveValue::CSS_EMS;
220     case UnitTypeFontXSize:
221         return CSSPrimitiveValue::CSS_EXS;
222     case UnitTypeRootFontSize:
223         return CSSPrimitiveValue::CSS_REMS;
224     case UnitTypePercentage:
225         return CSSPrimitiveValue::CSS_PERCENTAGE;
226     case UnitTypeViewportWidth:
227         return CSSPrimitiveValue::CSS_VW;
228     case UnitTypeViewportHeight:
229         return CSSPrimitiveValue::CSS_VH;
230     case UnitTypeViewportMin:
231         return CSSPrimitiveValue::CSS_VMIN;
232     case UnitTypeViewportMax:
233         return CSSPrimitiveValue::CSS_VMAX;
234     case UnitTypeCalc:
235         return CSSPrimitiveValue::CSS_UNKNOWN;
236     }
237     ASSERT_NOT_REACHED();
238     return CSSPrimitiveValue::CSS_UNKNOWN;
239 }
240 
241 } // namespace WebCore
242