blob: 150f7637e86235056dfac3c5cd93dee46b560b6b [file] [log] [blame]
// 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