blob: b9720e6a4f806a98743fbe7171dbdeda01a581d9 [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.
#include "core/animation/ShadowInterpolationFunctions.h"
#include "core/animation/CSSColorInterpolationType.h"
#include "core/animation/InterpolationValue.h"
#include "core/animation/LengthInterpolationFunctions.h"
#include "core/animation/NonInterpolableValue.h"
#include "core/css/CSSIdentifierValue.h"
#include "core/css/CSSShadowValue.h"
#include "core/css/resolver/StyleResolverState.h"
#include "core/style/ShadowData.h"
#include "platform/geometry/FloatPoint.h"
#include <memory>
namespace blink {
enum ShadowComponentIndex : unsigned {
ShadowX,
ShadowY,
ShadowBlur,
ShadowSpread,
ShadowColor,
ShadowComponentIndexCount,
};
class ShadowNonInterpolableValue : public NonInterpolableValue {
public:
~ShadowNonInterpolableValue() final {}
static PassRefPtr<ShadowNonInterpolableValue> create(
ShadowStyle shadowStyle) {
return adoptRef(new ShadowNonInterpolableValue(shadowStyle));
}
ShadowStyle style() const { return m_style; }
DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
private:
ShadowNonInterpolableValue(ShadowStyle shadowStyle) : m_style(shadowStyle) {}
ShadowStyle m_style;
};
DEFINE_NON_INTERPOLABLE_VALUE_TYPE(ShadowNonInterpolableValue);
DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(ShadowNonInterpolableValue);
bool ShadowInterpolationFunctions::nonInterpolableValuesAreCompatible(
const NonInterpolableValue* a,
const NonInterpolableValue* b) {
return toShadowNonInterpolableValue(*a).style() ==
toShadowNonInterpolableValue(*b).style();
}
PairwiseInterpolationValue ShadowInterpolationFunctions::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 ShadowInterpolationFunctions::convertShadowData(
const ShadowData& shadowData,
double zoom) {
std::unique_ptr<InterpolableList> interpolableList =
InterpolableList::create(ShadowComponentIndexCount);
interpolableList->set(ShadowX,
LengthInterpolationFunctions::createInterpolablePixels(
shadowData.x() / zoom));
interpolableList->set(ShadowY,
LengthInterpolationFunctions::createInterpolablePixels(
shadowData.y() / zoom));
interpolableList->set(ShadowBlur,
LengthInterpolationFunctions::createInterpolablePixels(
shadowData.blur() / zoom));
interpolableList->set(ShadowSpread,
LengthInterpolationFunctions::createInterpolablePixels(
shadowData.spread() / zoom));
interpolableList->set(
ShadowColor,
CSSColorInterpolationType::createInterpolableColor(shadowData.color()));
return InterpolationValue(
std::move(interpolableList),
ShadowNonInterpolableValue::create(shadowData.style()));
}
InterpolationValue ShadowInterpolationFunctions::maybeConvertCSSValue(
const CSSValue& value) {
if (!value.isShadowValue())
return nullptr;
const CSSShadowValue& shadow = toCSSShadowValue(value);
ShadowStyle style = Normal;
if (shadow.style) {
if (shadow.style->getValueID() == CSSValueInset)
style = Inset;
else
return nullptr;
}
std::unique_ptr<InterpolableList> interpolableList =
InterpolableList::create(ShadowComponentIndexCount);
static_assert(ShadowX == 0, "Enum ordering check.");
static_assert(ShadowY == 1, "Enum ordering check.");
static_assert(ShadowBlur == 2, "Enum ordering check.");
static_assert(ShadowSpread == 3, "Enum ordering check.");
const CSSPrimitiveValue* lengths[] = {
shadow.x.get(), shadow.y.get(), shadow.blur.get(), shadow.spread.get(),
};
for (size_t i = 0; i < WTF_ARRAY_LENGTH(lengths); i++) {
if (lengths[i]) {
InterpolationValue lengthField =
LengthInterpolationFunctions::maybeConvertCSSValue(*lengths[i]);
if (!lengthField)
return nullptr;
DCHECK(!lengthField.nonInterpolableValue);
interpolableList->set(i, std::move(lengthField.interpolableValue));
} else {
interpolableList->set(
i, LengthInterpolationFunctions::createInterpolablePixels(0));
}
}
if (shadow.color) {
std::unique_ptr<InterpolableValue> interpolableColor =
CSSColorInterpolationType::maybeCreateInterpolableColor(*shadow.color);
if (!interpolableColor)
return nullptr;
interpolableList->set(ShadowColor, std::move(interpolableColor));
} else {
interpolableList->set(ShadowColor,
CSSColorInterpolationType::createInterpolableColor(
StyleColor::currentColor()));
}
return InterpolationValue(std::move(interpolableList),
ShadowNonInterpolableValue::create(style));
}
std::unique_ptr<InterpolableValue>
ShadowInterpolationFunctions::createNeutralInterpolableValue() {
return convertShadowData(ShadowData(FloatPoint(0, 0), 0, 0, Normal,
StyleColor(Color::transparent)),
1)
.interpolableValue;
}
void ShadowInterpolationFunctions::composite(
std::unique_ptr<InterpolableValue>& underlyingInterpolableValue,
RefPtr<NonInterpolableValue>& underlyingNonInterpolableValue,
double underlyingFraction,
const InterpolableValue& interpolableValue,
const NonInterpolableValue* nonInterpolableValue) {
DCHECK(nonInterpolableValuesAreCompatible(
underlyingNonInterpolableValue.get(), nonInterpolableValue));
InterpolableList& underlyingInterpolableList =
toInterpolableList(*underlyingInterpolableValue);
const InterpolableList& interpolableList =
toInterpolableList(interpolableValue);
underlyingInterpolableList.scaleAndAdd(underlyingFraction, interpolableList);
}
ShadowData ShadowInterpolationFunctions::createShadowData(
const InterpolableValue& interpolableValue,
const NonInterpolableValue* nonInterpolableValue,
const StyleResolverState& state) {
const InterpolableList& interpolableList =
toInterpolableList(interpolableValue);
const ShadowNonInterpolableValue& shadowNonInterpolableValue =
toShadowNonInterpolableValue(*nonInterpolableValue);
const CSSToLengthConversionData& conversionData =
state.cssToLengthConversionData();
Length shadowX = LengthInterpolationFunctions::createLength(
*interpolableList.get(ShadowX), nullptr, conversionData, ValueRangeAll);
Length shadowY = LengthInterpolationFunctions::createLength(
*interpolableList.get(ShadowY), nullptr, conversionData, ValueRangeAll);
Length shadowBlur = LengthInterpolationFunctions::createLength(
*interpolableList.get(ShadowBlur), nullptr, conversionData,
ValueRangeNonNegative);
Length shadowSpread = LengthInterpolationFunctions::createLength(
*interpolableList.get(ShadowSpread), nullptr, conversionData,
ValueRangeAll);
DCHECK(shadowX.isFixed() && shadowY.isFixed() && shadowBlur.isFixed() &&
shadowSpread.isFixed());
return ShadowData(FloatPoint(shadowX.value(), shadowY.value()),
shadowBlur.value(), shadowSpread.value(),
shadowNonInterpolableValue.style(),
CSSColorInterpolationType::resolveInterpolableColor(
*interpolableList.get(ShadowColor), state));
}
} // namespace blink