| // Copyright 2015 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. |
| |
| #ifndef ListStyleInterpolation_h |
| #define ListStyleInterpolation_h |
| |
| #include "core/animation/StyleInterpolation.h" |
| #include "core/css/CSSPrimitiveValue.h" |
| #include "core/css/CSSValueList.h" |
| #include "core/css/resolver/StyleBuilder.h" |
| |
| namespace blink { |
| |
| template<typename InterpolationType, typename NonInterpolableData> |
| class ListStyleInterpolationImpl : public StyleInterpolation { |
| public: |
| static PassRefPtr<ListStyleInterpolationImpl<InterpolationType, NonInterpolableData>> maybeCreateFromList(const CSSValue& start, const CSSValue& end, CSSPropertyID id, InterpolationRange range = RangeAll) |
| { |
| if (start.isValueList() && end.isValueList() && toCSSValueList(start).length() == toCSSValueList(end).length()) { |
| const CSSValueList& startList = toCSSValueList(start); |
| const CSSValueList& endList = toCSSValueList(end); |
| |
| for (size_t i = 0; i < toCSSValueList(start).length(); i++) { |
| if (!InterpolationType::canCreateFrom(*startList.item(i), *endList.item(i))) { |
| return nullptr; |
| } |
| } |
| |
| Vector<typename InterpolationType::NonInterpolableType> startNonInterpolableData; |
| |
| OwnPtr<InterpolableValue> startValue = listToInterpolableValue(start, &startNonInterpolableData); |
| OwnPtr<InterpolableValue> endValue = listToInterpolableValue(end); |
| |
| return adoptRef(new ListStyleInterpolationImpl<InterpolationType, NonInterpolableData>(startValue.release(), endValue.release(), id, startNonInterpolableData, range)); |
| } |
| return nullptr; |
| } |
| |
| void apply(StyleResolverState& state) const override |
| { |
| StyleBuilder::applyProperty(m_id, state, interpolableValueToList(m_cachedValue.get(), m_nonInterpolableData, m_range).get()); |
| } |
| |
| private: |
| ListStyleInterpolationImpl(PassOwnPtr<InterpolableValue> start, PassOwnPtr<InterpolableValue> end, CSSPropertyID id, |
| Vector<typename InterpolationType::NonInterpolableType> nonInterpolableData, InterpolationRange range = RangeAll) |
| : StyleInterpolation(start, end, id) |
| , m_range(range) |
| { |
| m_nonInterpolableData.swap(nonInterpolableData); |
| } |
| |
| InterpolationRange m_range; |
| |
| Vector<typename InterpolationType::NonInterpolableType> m_nonInterpolableData; |
| |
| static PassOwnPtr<InterpolableValue> listToInterpolableValue(const CSSValue& value, Vector<typename InterpolationType::NonInterpolableType>* nonInterpolableData = nullptr) |
| { |
| const CSSValueList& listValue = toCSSValueList(value); |
| if (nonInterpolableData) |
| nonInterpolableData->reserveCapacity(listValue.length()); |
| OwnPtr<InterpolableList> result = InterpolableList::create(listValue.length()); |
| typename InterpolationType::NonInterpolableType elementData = typename InterpolationType::NonInterpolableType(); |
| for (size_t i = 0; i < listValue.length(); i++) { |
| result->set(i, InterpolationType::toInterpolableValue(*listValue.item(i), elementData)); |
| if (nonInterpolableData) |
| nonInterpolableData->append(elementData); |
| } |
| return result.release(); |
| } |
| |
| static PassRefPtrWillBeRawPtr<CSSValue> interpolableValueToList(InterpolableValue* value, const Vector<typename InterpolationType::NonInterpolableType>& nonInterpolableData, InterpolationRange range = RangeAll) |
| { |
| InterpolableList* listValue = toInterpolableList(value); |
| RefPtrWillBeRawPtr<CSSValueList> result = CSSValueList::createCommaSeparated(); |
| |
| ASSERT(nonInterpolableData.size() == listValue->length()); |
| |
| for (size_t i = 0; i < listValue->length(); i++) |
| result->append(InterpolationType::fromInterpolableValue(*(listValue->get(i)), nonInterpolableData[i], range)); |
| return result.release(); |
| } |
| |
| friend class ListStyleInterpolationTest; |
| }; |
| |
| template<typename InterpolationType> |
| class ListStyleInterpolationImpl<InterpolationType, void> : public StyleInterpolation { |
| public: |
| static PassRefPtr<ListStyleInterpolationImpl<InterpolationType, void>> maybeCreateFromList(const CSSValue& start, const CSSValue& end, CSSPropertyID id, InterpolationRange range = RangeAll) |
| { |
| if (!start.isValueList() || !end.isValueList()) |
| return nullptr; |
| const CSSValueList& startList = toCSSValueList(start); |
| const CSSValueList& endList = toCSSValueList(end); |
| if (startList.length() != endList.length()) |
| return nullptr; |
| for (const auto& value : startList) { |
| if (!InterpolationType::canCreateFrom(*value)) |
| return nullptr; |
| } |
| for (const auto& value : endList) { |
| if (!InterpolationType::canCreateFrom(*value)) |
| return nullptr; |
| } |
| return adoptRef(new ListStyleInterpolationImpl<InterpolationType, void>(listToInterpolableValue(start), listToInterpolableValue(end), id, range)); |
| } |
| |
| private: |
| ListStyleInterpolationImpl(PassOwnPtr<InterpolableValue> start, PassOwnPtr<InterpolableValue> end, CSSPropertyID id, InterpolationRange range = RangeAll) |
| : StyleInterpolation(start, end, id), m_range(range) |
| { |
| } |
| |
| InterpolationRange m_range; |
| |
| static PassOwnPtr<InterpolableValue> listToInterpolableValue(const CSSValue& value) |
| { |
| const CSSValueList& listValue = toCSSValueList(value); |
| OwnPtr<InterpolableList> result = InterpolableList::create(listValue.length()); |
| for (size_t i = 0; i < listValue.length(); i++) |
| result->set(i, InterpolationType::toInterpolableValue(*listValue.item(i))); |
| return result.release(); |
| } |
| |
| static PassRefPtrWillBeRawPtr<CSSValue> interpolableValueToList(InterpolableValue* value, InterpolationRange range = RangeAll) |
| { |
| InterpolableList* listValue = toInterpolableList(value); |
| RefPtrWillBeRawPtr<CSSValueList> result = CSSValueList::createCommaSeparated(); |
| |
| for (size_t i = 0; i < listValue->length(); i++) |
| result->append(InterpolationType::fromInterpolableValue(*(listValue->get(i)), range)); |
| return result.release(); |
| } |
| |
| void apply(StyleResolverState& state) const override |
| { |
| StyleBuilder::applyProperty(m_id, state, interpolableValueToList(m_cachedValue.get(), m_range).get()); |
| } |
| |
| friend class ListStyleInterpolationTest; |
| |
| }; |
| |
| template<typename InterpolationType> |
| class ListStyleInterpolation { |
| public: |
| static PassRefPtr<ListStyleInterpolationImpl<InterpolationType, typename InterpolationType::NonInterpolableType>> maybeCreateFromList(const CSSValue& start, const CSSValue& end, CSSPropertyID id, InterpolationRange range = RangeAll) |
| { |
| return ListStyleInterpolationImpl<InterpolationType, typename InterpolationType::NonInterpolableType>::maybeCreateFromList(start, end, id, range); |
| } |
| }; |
| |
| } // namespace blink |
| |
| #endif // ListStyleInterpolation_h |