Index: third_party/WebKit/Source/core/animation/LengthInterpolationFunctions.cpp |
diff --git a/third_party/WebKit/Source/core/animation/LengthInterpolationFunctions.cpp b/third_party/WebKit/Source/core/animation/LengthInterpolationFunctions.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f3565e6ad2b42285e045280e01ab7843dad0a824 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/animation/LengthInterpolationFunctions.cpp |
@@ -0,0 +1,169 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "core/animation/LengthInterpolationFunctions.h" |
+ |
+#include "core/css/CSSPrimitiveValue.h" |
+#include "core/css/CSSToLengthConversionData.h" |
+#include "platform/CalculationValue.h" |
+ |
+namespace blink { |
+ |
+// This class is implemented as a singleton whose instance represents the presence of percentages being used in a Length value |
+// while nullptr represents the absence of any percentages. |
+class CSSLengthNonInterpolableValue : public NonInterpolableValue { |
+public: |
+ ~CSSLengthNonInterpolableValue() final { NOTREACHED(); } |
+ static PassRefPtr<CSSLengthNonInterpolableValue> create(bool hasPercentage) |
+ { |
+ DEFINE_STATIC_REF(CSSLengthNonInterpolableValue, singleton, adoptRef(new CSSLengthNonInterpolableValue())); |
+ DCHECK(singleton); |
+ return hasPercentage ? singleton : nullptr; |
+ } |
+ static PassRefPtr<CSSLengthNonInterpolableValue> merge(const NonInterpolableValue* a, const NonInterpolableValue* b) |
+ { |
+ return create(hasPercentage(a) || hasPercentage(b)); |
+ } |
+ static bool hasPercentage(const NonInterpolableValue*); |
+ |
+ DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); |
+ |
+private: |
+ CSSLengthNonInterpolableValue() { } |
+}; |
+ |
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSLengthNonInterpolableValue); |
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(CSSLengthNonInterpolableValue); |
+ |
+bool CSSLengthNonInterpolableValue::hasPercentage(const NonInterpolableValue* nonInterpolableValue) |
+{ |
+ DCHECK(isCSSLengthNonInterpolableValue(nonInterpolableValue)); |
+ return static_cast<bool>(nonInterpolableValue); |
+} |
+ |
+std::unique_ptr<InterpolableValue> LengthInterpolationFunctions::createInterpolablePixels(double pixels) |
+{ |
+ std::unique_ptr<InterpolableList> interpolableList = createNeutralInterpolableValue(); |
+ interpolableList->set(CSSPrimitiveValue::UnitTypePixels, InterpolableNumber::create(pixels)); |
+ return std::move(interpolableList); |
+} |
+ |
+InterpolationValue LengthInterpolationFunctions::createInterpolablePercent(double percent) |
+{ |
+ std::unique_ptr<InterpolableList> interpolableList = createNeutralInterpolableValue(); |
+ interpolableList->set(CSSPrimitiveValue::UnitTypePercentage, InterpolableNumber::create(percent)); |
+ return InterpolationValue(std::move(interpolableList), CSSLengthNonInterpolableValue::create(true)); |
+} |
+ |
+std::unique_ptr<InterpolableList> LengthInterpolationFunctions::createNeutralInterpolableValue() |
+{ |
+ const size_t length = CSSPrimitiveValue::LengthUnitTypeCount; |
+ std::unique_ptr<InterpolableList> values = InterpolableList::create(length); |
+ for (size_t i = 0; i < length; i++) |
+ values->set(i, InterpolableNumber::create(0)); |
+ return values; |
+} |
+ |
+InterpolationValue LengthInterpolationFunctions::maybeConvertCSSValue(const CSSValue& value) |
+{ |
+ if (!value.isPrimitiveValue()) |
+ return nullptr; |
+ |
+ const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
+ if (!primitiveValue.isLength() && !primitiveValue.isPercentage() && !primitiveValue.isCalculatedPercentageWithLength()) |
+ return nullptr; |
+ |
+ CSSLengthArray lengthArray; |
+ primitiveValue.accumulateLengthArray(lengthArray); |
+ |
+ std::unique_ptr<InterpolableList> values = InterpolableList::create(CSSPrimitiveValue::LengthUnitTypeCount); |
+ for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) |
+ values->set(i, InterpolableNumber::create(lengthArray.values[i])); |
+ |
+ bool hasPercentage = lengthArray.typeFlags.get(CSSPrimitiveValue::UnitTypePercentage); |
+ return InterpolationValue(std::move(values), CSSLengthNonInterpolableValue::create(hasPercentage)); |
+} |
+ |
+InterpolationValue LengthInterpolationFunctions::maybeConvertLength(const Length& length, float zoom) |
+{ |
+ if (!length.isSpecified()) |
+ return nullptr; |
+ |
+ PixelsAndPercent pixelsAndPercent = length.getPixelsAndPercent(); |
+ std::unique_ptr<InterpolableList> values = createNeutralInterpolableValue(); |
+ values->set(CSSPrimitiveValue::UnitTypePixels, InterpolableNumber::create(pixelsAndPercent.pixels / zoom)); |
+ values->set(CSSPrimitiveValue::UnitTypePercentage, InterpolableNumber::create(pixelsAndPercent.percent)); |
+ |
+ return InterpolationValue(std::move(values), CSSLengthNonInterpolableValue::create(length.isPercentOrCalc())); |
+} |
+ |
+PairwiseInterpolationValue LengthInterpolationFunctions::mergeSingles(InterpolationValue&& start, InterpolationValue&& end) |
+{ |
+ return PairwiseInterpolationValue( |
+ std::move(start.interpolableValue), |
+ std::move(end.interpolableValue), |
+ CSSLengthNonInterpolableValue::merge(start.nonInterpolableValue.get(), end.nonInterpolableValue.get())); |
+} |
+ |
+bool LengthInterpolationFunctions::nonInterpolableValuesAreCompatible(const NonInterpolableValue* a, const NonInterpolableValue* b) |
+{ |
+ DCHECK(isCSSLengthNonInterpolableValue(a)); |
+ DCHECK(isCSSLengthNonInterpolableValue(b)); |
+ return true; |
+} |
+ |
+void LengthInterpolationFunctions::composite( |
+ std::unique_ptr<InterpolableValue>& underlyingInterpolableValue, |
+ RefPtr<NonInterpolableValue>& underlyingNonInterpolableValue, |
+ double underlyingFraction, |
+ const InterpolableValue& interpolableValue, |
+ const NonInterpolableValue* nonInterpolableValue) |
+{ |
+ underlyingInterpolableValue->scaleAndAdd(underlyingFraction, interpolableValue); |
+ underlyingNonInterpolableValue = CSSLengthNonInterpolableValue::merge(underlyingNonInterpolableValue.get(), nonInterpolableValue); |
+} |
+ |
+void LengthInterpolationFunctions::subtractFromOneHundredPercent(InterpolationValue& result) |
+{ |
+ InterpolableList& list = toInterpolableList(*result.interpolableValue); |
+ for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { |
+ double value = -toInterpolableNumber(*list.get(i)).value(); |
+ if (i == CSSPrimitiveValue::UnitTypePercentage) |
+ value += 100; |
+ toInterpolableNumber(*list.getMutable(i)).set(value); |
+ } |
+ result.nonInterpolableValue = CSSLengthNonInterpolableValue::create(true); |
+} |
+ |
+static double clampToRange(double x, ValueRange range) |
+{ |
+ return (range == ValueRangeNonNegative && x < 0) ? 0 : x; |
+} |
+ |
+Length LengthInterpolationFunctions::createLength(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, const CSSToLengthConversionData& conversionData, ValueRange range) |
+{ |
+ const InterpolableList& interpolableList = toInterpolableList(interpolableValue); |
+ bool hasPercentage = CSSLengthNonInterpolableValue::hasPercentage(nonInterpolableValue); |
+ double pixels = 0; |
+ double percentage = 0; |
+ for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { |
+ double value = toInterpolableNumber(*interpolableList.get(i)).value(); |
+ if (i == CSSPrimitiveValue::UnitTypePercentage) { |
+ percentage = value; |
+ } else { |
+ CSSPrimitiveValue::UnitType type = CSSPrimitiveValue::lengthUnitTypeToUnitType(static_cast<CSSPrimitiveValue::LengthUnitType>(i)); |
+ pixels += conversionData.zoomedComputedPixels(value, type); |
+ } |
+ } |
+ |
+ if (percentage != 0) |
+ hasPercentage = true; |
+ if (pixels != 0 && hasPercentage) |
+ return Length(CalculationValue::create(PixelsAndPercent(pixels, percentage), range)); |
+ if (hasPercentage) |
+ return Length(clampToRange(percentage, range), Percent); |
+ return Length(CSSPrimitiveValue::clampToCSSLengthRange(clampToRange(pixels, range)), Fixed); |
+} |
+ |
+} // namespace blink |