blob: ef4da31b19158422a2e05d93b017c07c8e65ed6b [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 "config.h"
#include "core/animation/ShadowInterpolationFunctions.h"
#include "core/animation/CSSColorInterpolationType.h"
#include "core/animation/CSSLengthInterpolationType.h"
#include "core/animation/InterpolationValue.h"
#include "core/animation/NonInterpolableValue.h"
#include "core/css/CSSShadowValue.h"
#include "core/css/resolver/StyleResolverState.h"
#include "core/style/ShadowData.h"
#include "platform/geometry/FloatPoint.h"
namespace blink {
enum ShadowComponentIndex {
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();
}
PairwiseInterpolationComponent ShadowInterpolationFunctions::mergeSingleConversions(InterpolationComponent& start, InterpolationComponent& end)
{
if (!nonInterpolableValuesAreCompatible(start.nonInterpolableValue.get(), end.nonInterpolableValue.get()))
return nullptr;
return PairwiseInterpolationComponent(start.interpolableValue.release(), end.interpolableValue.release(), start.nonInterpolableValue.release());
}
InterpolationComponent ShadowInterpolationFunctions::convertShadowData(const ShadowData& shadowData, double zoom)
{
OwnPtr<InterpolableList> interpolableList = InterpolableList::create(ShadowComponentIndexCount);
interpolableList->set(ShadowX, CSSLengthInterpolationType::createInterpolablePixels(shadowData.x() / zoom));
interpolableList->set(ShadowY, CSSLengthInterpolationType::createInterpolablePixels(shadowData.y() / zoom));
interpolableList->set(ShadowBlur, CSSLengthInterpolationType::createInterpolablePixels(shadowData.blur() / zoom));
interpolableList->set(ShadowSpread, CSSLengthInterpolationType::createInterpolablePixels(shadowData.spread() / zoom));
interpolableList->set(ShadowColor, CSSColorInterpolationType::createInterpolableColor(shadowData.color()));
return InterpolationComponent(interpolableList.release(), ShadowNonInterpolableValue::create(shadowData.style()));
}
InterpolationComponent 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;
}
OwnPtr<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]) {
InterpolationComponent component = CSSLengthInterpolationType::maybeConvertCSSValue(*lengths[i]);
if (!component)
return nullptr;
ASSERT(!component.nonInterpolableValue);
interpolableList->set(i, component.interpolableValue.release());
} else {
interpolableList->set(i, CSSLengthInterpolationType::createInterpolablePixels(0));
}
}
if (shadow.color) {
OwnPtr<InterpolableValue> interpolableColor = CSSColorInterpolationType::maybeCreateInterpolableColor(*shadow.color);
if (!interpolableColor)
return nullptr;
interpolableList->set(ShadowColor, interpolableColor.release());
} else {
interpolableList->set(ShadowColor, CSSColorInterpolationType::createInterpolableColor(StyleColor::currentColor()));
}
return InterpolationComponent(interpolableList.release(), ShadowNonInterpolableValue::create(style));
}
void ShadowInterpolationFunctions::composite(OwnPtr<InterpolableValue>& underlyingInterpolableValue, RefPtr<NonInterpolableValue>& underlyingNonInterpolableValue, double underlyingFraction, const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue)
{
ASSERT(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 = CSSLengthInterpolationType::resolveInterpolableLength(*interpolableList.get(ShadowX), nullptr, conversionData);
Length shadowY = CSSLengthInterpolationType::resolveInterpolableLength(*interpolableList.get(ShadowY), nullptr, conversionData);
Length shadowBlur = CSSLengthInterpolationType::resolveInterpolableLength(*interpolableList.get(ShadowBlur), nullptr, conversionData, ValueRangeNonNegative);
Length shadowSpread = CSSLengthInterpolationType::resolveInterpolableLength(*interpolableList.get(ShadowSpread), nullptr, conversionData);
ASSERT(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