2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "core/animation/AnimatableLength.h"
34 #include "core/css/CSSPrimitiveValueMappings.h"
35 #include "platform/CalculationValue.h"
36 #include "platform/animation/AnimationUtilities.h"
40 PassRefPtr<AnimatableLength> AnimatableLength::create(CSSValue* value)
42 ASSERT(canCreateFrom(value));
43 if (value->isPrimitiveValue()) {
44 CSSPrimitiveValue* primitiveValue = WebCore::toCSSPrimitiveValue(value);
45 const CSSCalcValue* calcValue = primitiveValue->cssCalcValue();
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);
55 if (value->isCalcValue())
56 return create(toCSSCalcValue(value)->expressionNode());
62 bool AnimatableLength::canCreateFrom(const CSSValue* value)
65 if (value->isPrimitiveValue()) {
66 const CSSPrimitiveValue* primitiveValue = WebCore::toCSSPrimitiveValue(value);
67 if (primitiveValue->cssCalcValue())
70 NumberUnitType unitType;
71 // Only returns true if the type is a primitive length unit.
72 return primitiveUnitToNumberType(primitiveValue->primitiveType(), unitType);
74 return value->isCalcValue();
77 PassRefPtr<CSSValue> AnimatableLength::toCSSValue(NumberRange range) const
79 return toCSSPrimitiveValue(range);
82 Length AnimatableLength::toLength(const CSSToLengthConversionData& conversionData, NumberRange range) const
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);
90 return toCSSPrimitiveValue(range)->convertToLength<AnyConversion>(conversionData);
93 bool AnimatableLength::usesDefaultInterpolationWith(const AnimatableValue* value) const
95 const AnimatableLength* length = toAnimatableLength(value);
96 NumberUnitType type = commonUnitType(length);
97 return type == UnitTypeCalc && (isViewportUnit() || length->isViewportUnit());
100 PassRefPtr<AnimatableValue> AnimatableLength::interpolateTo(const AnimatableValue* value, double fraction) const
102 const AnimatableLength* length = toAnimatableLength(value);
103 NumberUnitType type = commonUnitType(length);
104 if (type != UnitTypeCalc)
105 return AnimatableLength::create(blend(m_number, length->m_number, fraction), type);
107 // FIXME(crbug.com/168840): Support for viewport units in calc needs to be added before we can blend them with other units.
108 if (isViewportUnit() || length->isViewportUnit())
109 return defaultInterpolateTo(this, value, fraction);
111 return AnimatableLength::create(scale(1 - fraction).get(), length->scale(fraction).get());
114 PassRefPtr<AnimatableValue> AnimatableLength::addWith(const AnimatableValue* value) const
116 // Optimization for adding with 0.
117 if (isUnitlessZero())
118 return takeConstRef(value);
120 const AnimatableLength* length = toAnimatableLength(value);
121 if (length->isUnitlessZero())
122 return takeConstRef(this);
124 NumberUnitType type = commonUnitType(length);
125 if (type != UnitTypeCalc)
126 return AnimatableLength::create(m_number + length->m_number, type);
128 return AnimatableLength::create(this, length);
131 bool AnimatableLength::equalTo(const AnimatableValue* value) const
133 const AnimatableLength* length = toAnimatableLength(value);
134 if (m_unitType != length->m_unitType)
137 return m_calcExpression == length->m_calcExpression || m_calcExpression->equals(*length->m_calcExpression);
138 return m_number == length->m_number;
141 PassRefPtr<CSSCalcExpressionNode> AnimatableLength::toCSSCalcExpressionNode() const
144 return m_calcExpression;
145 return CSSCalcValue::createExpressionNode(toCSSPrimitiveValue(AllValues), m_number == trunc(m_number));
148 static bool isCompatibleWithRange(const CSSPrimitiveValue* primitiveValue, NumberRange range)
150 ASSERT(primitiveValue);
151 if (range == AllValues)
153 if (primitiveValue->isCalculated())
154 return primitiveValue->cssCalcValue()->permittedValueRange() == ValueRangeNonNegative;
155 return primitiveValue->getDoubleValue() >= 0;
158 PassRefPtr<CSSPrimitiveValue> AnimatableLength::toCSSPrimitiveValue(NumberRange range) const
160 if (!m_cachedCSSPrimitiveValue || !isCompatibleWithRange(m_cachedCSSPrimitiveValue.get(), range)) {
162 m_cachedCSSPrimitiveValue = CSSPrimitiveValue::create(CSSCalcValue::create(m_calcExpression, range == AllValues ? ValueRangeAll : ValueRangeNonNegative));
164 m_cachedCSSPrimitiveValue = CSSPrimitiveValue::create(clampedNumber(range), static_cast<CSSPrimitiveValue::UnitTypes>(numberTypeToPrimitiveUnit(m_unitType)));
166 return m_cachedCSSPrimitiveValue;
169 PassRefPtr<AnimatableLength> AnimatableLength::scale(double factor) const
172 return AnimatableLength::create(CSSCalcValue::createExpressionNode(
174 CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(factor, CSSPrimitiveValue::CSS_NUMBER)),
177 return AnimatableLength::create(m_number * factor, m_unitType);
180 bool AnimatableLength::primitiveUnitToNumberType(unsigned short primitiveUnit, NumberUnitType& numberType)
182 switch (primitiveUnit) {
183 case CSSPrimitiveValue::CSS_PX:
184 case CSSPrimitiveValue::CSS_CM:
185 case CSSPrimitiveValue::CSS_MM:
186 case CSSPrimitiveValue::CSS_IN:
187 case CSSPrimitiveValue::CSS_PT:
188 case CSSPrimitiveValue::CSS_PC:
189 numberType = UnitTypePixels;
191 case CSSPrimitiveValue::CSS_EMS:
192 numberType = UnitTypeFontSize;
194 case CSSPrimitiveValue::CSS_EXS:
195 numberType = UnitTypeFontXSize;
197 case CSSPrimitiveValue::CSS_REMS:
198 numberType = UnitTypeRootFontSize;
200 case CSSPrimitiveValue::CSS_PERCENTAGE:
201 numberType = UnitTypePercentage;
203 case CSSPrimitiveValue::CSS_VW:
204 numberType = UnitTypeViewportWidth;
206 case CSSPrimitiveValue::CSS_VH:
207 numberType = UnitTypeViewportHeight;
209 case CSSPrimitiveValue::CSS_VMIN:
210 numberType = UnitTypeViewportMin;
212 case CSSPrimitiveValue::CSS_VMAX:
213 numberType = UnitTypeViewportMax;
220 unsigned short AnimatableLength::numberTypeToPrimitiveUnit(NumberUnitType numberType)
222 switch (numberType) {
224 return CSSPrimitiveValue::CSS_PX;
225 case UnitTypeFontSize:
226 return CSSPrimitiveValue::CSS_EMS;
227 case UnitTypeFontXSize:
228 return CSSPrimitiveValue::CSS_EXS;
229 case UnitTypeRootFontSize:
230 return CSSPrimitiveValue::CSS_REMS;
231 case UnitTypePercentage:
232 return CSSPrimitiveValue::CSS_PERCENTAGE;
233 case UnitTypeViewportWidth:
234 return CSSPrimitiveValue::CSS_VW;
235 case UnitTypeViewportHeight:
236 return CSSPrimitiveValue::CSS_VH;
237 case UnitTypeViewportMin:
238 return CSSPrimitiveValue::CSS_VMIN;
239 case UnitTypeViewportMax:
240 return CSSPrimitiveValue::CSS_VMAX;
242 return CSSPrimitiveValue::CSS_UNKNOWN;
244 ASSERT_NOT_REACHED();
245 return CSSPrimitiveValue::CSS_UNKNOWN;
248 } // namespace WebCore