blob: e6158e08f263ee7e4f982c315f2fe15b4de9b66e [file] [log] [blame]
// 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/CSSSizeListInterpolationType.h"
#include "core/animation/ListInterpolationFunctions.h"
#include "core/animation/SizeInterpolationFunctions.h"
#include "core/animation/SizeListPropertyFunctions.h"
#include "core/css/CSSValueList.h"
#include "core/css/resolver/StyleResolverState.h"
namespace blink {
class UnderlyingSizeListChecker : public InterpolationType::ConversionChecker {
public:
~UnderlyingSizeListChecker() final {}
static std::unique_ptr<UnderlyingSizeListChecker> create(
const NonInterpolableList& underlyingList) {
return WTF::wrapUnique(new UnderlyingSizeListChecker(underlyingList));
}
private:
UnderlyingSizeListChecker(const NonInterpolableList& underlyingList)
: m_underlyingList(&underlyingList) {}
bool isValid(const InterpolationEnvironment&,
const InterpolationValue& underlying) const final {
const auto& underlyingList =
toNonInterpolableList(*underlying.nonInterpolableValue);
size_t underlyingLength = underlyingList.length();
if (underlyingLength != m_underlyingList->length())
return false;
for (size_t i = 0; i < underlyingLength; i++) {
bool compatible =
SizeInterpolationFunctions::nonInterpolableValuesAreCompatible(
underlyingList.get(i), m_underlyingList->get(i));
if (!compatible)
return false;
}
return true;
}
RefPtr<const NonInterpolableList> m_underlyingList;
};
class InheritedSizeListChecker : public InterpolationType::ConversionChecker {
public:
~InheritedSizeListChecker() final {}
static std::unique_ptr<InheritedSizeListChecker> create(
CSSPropertyID property,
const SizeList& inheritedSizeList) {
return WTF::wrapUnique(
new InheritedSizeListChecker(property, inheritedSizeList));
}
private:
InheritedSizeListChecker(CSSPropertyID property,
const SizeList& inheritedSizeList)
: m_property(property), m_inheritedSizeList(inheritedSizeList) {}
bool isValid(const InterpolationEnvironment& environment,
const InterpolationValue&) const final {
return m_inheritedSizeList ==
SizeListPropertyFunctions::getSizeList(
m_property, *environment.state().parentStyle());
}
CSSPropertyID m_property;
SizeList m_inheritedSizeList;
};
InterpolationValue convertSizeList(const SizeList& sizeList, float zoom) {
// Flatten pairs of width/height into individual items, even for contain and
// cover keywords.
return ListInterpolationFunctions::createList(
sizeList.size() * 2,
[&sizeList, zoom](size_t index) -> InterpolationValue {
bool convertWidth = index % 2 == 0;
return SizeInterpolationFunctions::convertFillSizeSide(
sizeList[index / 2], zoom, convertWidth);
});
}
InterpolationValue maybeConvertCSSSizeList(const CSSValue& value) {
// CSSPropertyParser doesn't put single values in lists so wrap it up in a
// temporary list.
const CSSValueList* list = nullptr;
if (!value.isBaseValueList()) {
CSSValueList* tempList = CSSValueList::createCommaSeparated();
tempList->append(value);
list = tempList;
} else {
list = toCSSValueList(&value);
}
// Flatten pairs of width/height into individual items, even for contain and
// cover keywords.
return ListInterpolationFunctions::createList(
list->length() * 2, [list](size_t index) -> InterpolationValue {
const CSSValue& cssSize = list->item(index / 2);
bool convertWidth = index % 2 == 0;
return SizeInterpolationFunctions::maybeConvertCSSSizeSide(
cssSize, convertWidth);
});
}
InterpolationValue CSSSizeListInterpolationType::maybeConvertNeutral(
const InterpolationValue& underlying,
ConversionCheckers& conversionCheckers) const {
const auto& underlyingList =
toNonInterpolableList(*underlying.nonInterpolableValue);
conversionCheckers.push_back(
UnderlyingSizeListChecker::create(underlyingList));
return ListInterpolationFunctions::createList(
underlyingList.length(), [&underlyingList](size_t index) {
return SizeInterpolationFunctions::createNeutralValue(
underlyingList.get(index));
});
}
InterpolationValue CSSSizeListInterpolationType::maybeConvertInitial(
const StyleResolverState&,
ConversionCheckers&) const {
return convertSizeList(
SizeListPropertyFunctions::getInitialSizeList(cssProperty()), 1);
}
InterpolationValue CSSSizeListInterpolationType::maybeConvertInherit(
const StyleResolverState& state,
ConversionCheckers& conversionCheckers) const {
SizeList inheritedSizeList = SizeListPropertyFunctions::getSizeList(
cssProperty(), *state.parentStyle());
conversionCheckers.push_back(
InheritedSizeListChecker::create(cssProperty(), inheritedSizeList));
return convertSizeList(inheritedSizeList, state.style()->effectiveZoom());
}
InterpolationValue CSSSizeListInterpolationType::maybeConvertValue(
const CSSValue& value,
const StyleResolverState&,
ConversionCheckers&) const {
return maybeConvertCSSSizeList(value);
}
PairwiseInterpolationValue CSSSizeListInterpolationType::maybeMergeSingles(
InterpolationValue&& start,
InterpolationValue&& end) const {
return ListInterpolationFunctions::maybeMergeSingles(
std::move(start), std::move(end),
SizeInterpolationFunctions::maybeMergeSingles);
}
InterpolationValue
CSSSizeListInterpolationType::maybeConvertStandardPropertyUnderlyingValue(
const StyleResolverState& state) const {
const ComputedStyle& style = *state.style();
return convertSizeList(
SizeListPropertyFunctions::getSizeList(cssProperty(), style),
style.effectiveZoom());
}
void CSSSizeListInterpolationType::composite(
UnderlyingValueOwner& underlyingValueOwner,
double underlyingFraction,
const InterpolationValue& value,
double interpolationFraction) const {
ListInterpolationFunctions::composite(
underlyingValueOwner, underlyingFraction, *this, value,
SizeInterpolationFunctions::nonInterpolableValuesAreCompatible,
SizeInterpolationFunctions::composite);
}
void CSSSizeListInterpolationType::applyStandardPropertyValue(
const InterpolableValue& interpolableValue,
const NonInterpolableValue* nonInterpolableValue,
StyleResolverState& state) const {
const auto& interpolableList = toInterpolableList(interpolableValue);
const auto& nonInterpolableList =
toNonInterpolableList(*nonInterpolableValue);
size_t length = interpolableList.length();
DCHECK_EQ(length, nonInterpolableList.length());
DCHECK_EQ(length % 2, 0ul);
size_t sizeListLength = length / 2;
SizeList sizeList(sizeListLength);
for (size_t i = 0; i < sizeListLength; i++) {
sizeList[i] = SizeInterpolationFunctions::createFillSize(
*interpolableList.get(i * 2), nonInterpolableList.get(i * 2),
*interpolableList.get(i * 2 + 1), nonInterpolableList.get(i * 2 + 1),
state.cssToLengthConversionData());
}
SizeListPropertyFunctions::setSizeList(cssProperty(), *state.style(),
sizeList);
}
} // namespace blink