Index: third_party/WebKit/Source/core/animation/SizeInterpolationFunctions.cpp |
diff --git a/third_party/WebKit/Source/core/animation/SizeInterpolationFunctions.cpp b/third_party/WebKit/Source/core/animation/SizeInterpolationFunctions.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..505ab0c45ef1c35cf7ca8ff82442de5979222ecb |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/animation/SizeInterpolationFunctions.cpp |
@@ -0,0 +1,186 @@ |
+// 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/SizeInterpolationFunctions.h" |
+ |
+#include "core/animation/LengthInterpolationFunctions.h" |
+#include "core/animation/UnderlyingValueOwner.h" |
+#include "core/css/CSSToLengthConversionData.h" |
+#include "core/css/CSSValuePair.h" |
+ |
+namespace blink { |
+ |
+class CSSSizeNonInterpolableValue : public NonInterpolableValue { |
+public: |
+ static PassRefPtr<CSSSizeNonInterpolableValue> create(CSSValueID keyword) |
+ { |
+ return adoptRef(new CSSSizeNonInterpolableValue(keyword)); |
+ } |
+ |
+ static PassRefPtr<CSSSizeNonInterpolableValue> create(PassRefPtr<NonInterpolableValue> lengthNonInterpolableValue) |
+ { |
+ return adoptRef(new CSSSizeNonInterpolableValue(lengthNonInterpolableValue)); |
+ } |
+ |
+ bool isKeyword() const { return m_keyword != CSSValueInvalid; } |
+ CSSValueID keyword() const { DCHECK(isKeyword()); return m_keyword; } |
+ |
+ const NonInterpolableValue* lengthNonInterpolableValue() const { DCHECK(!isKeyword()); return m_lengthNonInterpolableValue.get(); } |
+ RefPtr<NonInterpolableValue>& lengthNonInterpolableValue() { DCHECK(!isKeyword()); return m_lengthNonInterpolableValue; } |
+ |
+ DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); |
+ |
+private: |
+ CSSSizeNonInterpolableValue(CSSValueID keyword) |
+ : m_keyword(keyword) |
+ , m_lengthNonInterpolableValue(nullptr) |
+ { |
+ DCHECK_NE(keyword, CSSValueInvalid); |
+ } |
+ |
+ CSSSizeNonInterpolableValue(PassRefPtr<NonInterpolableValue> lengthNonInterpolableValue) |
+ : m_keyword(CSSValueInvalid) |
+ , m_lengthNonInterpolableValue(lengthNonInterpolableValue) |
+ { } |
+ |
+ CSSValueID m_keyword; |
+ RefPtr<NonInterpolableValue> m_lengthNonInterpolableValue; |
+}; |
+ |
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSSizeNonInterpolableValue); |
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(CSSSizeNonInterpolableValue); |
+ |
+static InterpolationValue convertKeyword(CSSValueID keyword) |
+{ |
+ return InterpolationValue(InterpolableList::create(0), CSSSizeNonInterpolableValue::create(keyword)); |
+} |
+ |
+static InterpolationValue wrapConvertedLength(InterpolationValue&& convertedLength) |
+{ |
+ if (!convertedLength) |
+ return nullptr; |
+ return InterpolationValue( |
+ std::move(convertedLength.interpolableValue), |
+ CSSSizeNonInterpolableValue::create(convertedLength.nonInterpolableValue.release())); |
+} |
+ |
+InterpolationValue SizeInterpolationFunctions::convertFillSizeSide(const FillSize& fillSize, float zoom, bool convertWidth) |
+{ |
+ switch (fillSize.type) { |
+ case SizeLength: { |
+ const Length& side = convertWidth ? fillSize.size.width() : fillSize.size.height(); |
+ if (side.isAuto()) |
+ return convertKeyword(CSSValueAuto); |
+ return wrapConvertedLength(LengthInterpolationFunctions::maybeConvertLength(side, zoom)); |
+ } |
+ case Contain: |
+ return convertKeyword(CSSValueContain); |
+ case Cover: |
+ return convertKeyword(CSSValueCover); |
+ case SizeNone: |
+ default: |
+ NOTREACHED(); |
+ return nullptr; |
+ } |
+} |
+ |
+InterpolationValue SizeInterpolationFunctions::maybeConvertCSSSizeSide(const CSSValue& value, bool convertWidth) |
+{ |
+ if (value.isValuePair()) { |
+ const CSSValuePair& pair = toCSSValuePair(value); |
+ const CSSValue& side = convertWidth ? pair.first() : pair.second(); |
+ if (side.isPrimitiveValue() && toCSSPrimitiveValue(side).getValueID() == CSSValueAuto) |
+ return convertKeyword(CSSValueAuto); |
+ return wrapConvertedLength(LengthInterpolationFunctions::maybeConvertCSSValue(side)); |
+ } |
+ |
+ if (!value.isPrimitiveValue()) |
+ return nullptr; |
+ CSSValueID keyword = toCSSPrimitiveValue(value).getValueID(); |
+ if (keyword) |
+ return convertKeyword(keyword); |
+ |
+ // A single length is equivalent to "<length> auto". |
+ if (convertWidth) |
+ return wrapConvertedLength(LengthInterpolationFunctions::maybeConvertCSSValue(value)); |
+ return convertKeyword(CSSValueAuto); |
+} |
+ |
+PairwiseInterpolationValue SizeInterpolationFunctions::maybeMergeSingles(InterpolationValue&& start, InterpolationValue&& end) |
+{ |
+ if (!nonInterpolableValuesAreCompatible(start.nonInterpolableValue.get(), end.nonInterpolableValue.get())) |
+ return nullptr; |
+ return PairwiseInterpolationValue( |
+ std::move(start.interpolableValue), |
+ std::move(end.interpolableValue), |
+ start.nonInterpolableValue.release()); |
+} |
+ |
+InterpolationValue SizeInterpolationFunctions::createNeutralValue(const NonInterpolableValue* nonInterpolableValue) |
+{ |
+ auto& size = toCSSSizeNonInterpolableValue(*nonInterpolableValue); |
+ if (size.isKeyword()) |
+ return convertKeyword(size.keyword()); |
+ return wrapConvertedLength(InterpolationValue(LengthInterpolationFunctions::createNeutralInterpolableValue())); |
+} |
+ |
+bool SizeInterpolationFunctions::nonInterpolableValuesAreCompatible(const NonInterpolableValue* a, const NonInterpolableValue* b) |
+{ |
+ const auto& sizeA = toCSSSizeNonInterpolableValue(*a); |
+ const auto& sizeB = toCSSSizeNonInterpolableValue(*b); |
+ if (sizeA.isKeyword() != sizeB.isKeyword()) |
+ return false; |
+ if (sizeA.isKeyword()) |
+ return sizeA.keyword() == sizeB.keyword(); |
+ return true; |
+} |
+ |
+void SizeInterpolationFunctions::composite(std::unique_ptr<InterpolableValue>& underlyingInterpolableValue, RefPtr<NonInterpolableValue>& underlyingNonInterpolableValue, double underlyingFraction, const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue) |
+{ |
+ const auto& sizeNonInterpolableValue = toCSSSizeNonInterpolableValue(*nonInterpolableValue); |
+ if (sizeNonInterpolableValue.isKeyword()) |
+ return; |
+ auto& underlyingSizeNonInterpolableValue = toCSSSizeNonInterpolableValue(*underlyingNonInterpolableValue); |
+ LengthInterpolationFunctions::composite( |
+ underlyingInterpolableValue, |
+ underlyingSizeNonInterpolableValue.lengthNonInterpolableValue(), |
+ underlyingFraction, |
+ interpolableValue, |
+ sizeNonInterpolableValue.lengthNonInterpolableValue()); |
+} |
+ |
+static Length createLength(const InterpolableValue& interpolableValue, const CSSSizeNonInterpolableValue& nonInterpolableValue, const CSSToLengthConversionData& conversionData) |
+{ |
+ if (nonInterpolableValue.isKeyword()) { |
+ DCHECK_EQ(nonInterpolableValue.keyword(), CSSValueAuto); |
+ return Length(Auto); |
+ } |
+ return LengthInterpolationFunctions::createLength(interpolableValue, nonInterpolableValue.lengthNonInterpolableValue(), conversionData, ValueRangeNonNegative); |
+} |
+ |
+FillSize SizeInterpolationFunctions::createFillSize(const InterpolableValue& interpolableValueA, const NonInterpolableValue* nonInterpolableValueA, const InterpolableValue& interpolableValueB, const NonInterpolableValue* nonInterpolableValueB, const CSSToLengthConversionData& conversionData) |
+{ |
+ const auto& sideA = toCSSSizeNonInterpolableValue(*nonInterpolableValueA); |
+ const auto& sideB = toCSSSizeNonInterpolableValue(*nonInterpolableValueB); |
+ if (sideA.isKeyword()) { |
+ switch (sideA.keyword()) { |
+ case CSSValueCover: |
+ DCHECK_EQ(sideA.keyword(), sideB.keyword()); |
+ return FillSize(Cover, LengthSize()); |
+ case CSSValueContain: |
+ DCHECK_EQ(sideA.keyword(), sideB.keyword()); |
+ return FillSize(Contain, LengthSize()); |
+ case CSSValueAuto: |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ } |
+ return FillSize(SizeLength, LengthSize( |
+ createLength(interpolableValueA, sideA, conversionData), |
+ createLength(interpolableValueB, sideB, conversionData))); |
+} |
+ |
+} // namespace blink |