blob: 54cb2e98b86e919216404e4b16aa89dead88440d [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/CSSVisibilityInterpolationType.h"
#include "core/css/CSSPrimitiveValueMappings.h"
#include "core/css/resolver/StyleResolverState.h"
#include "wtf/PtrUtil.h"
#include <memory>
namespace blink {
class CSSVisibilityNonInterpolableValue : public NonInterpolableValue {
public:
~CSSVisibilityNonInterpolableValue() final {}
static PassRefPtr<CSSVisibilityNonInterpolableValue> create(EVisibility start,
EVisibility end) {
return adoptRef(new CSSVisibilityNonInterpolableValue(start, end));
}
EVisibility visibility() const {
DCHECK(m_isSingle);
return m_start;
}
EVisibility visibility(double fraction) const {
if (m_isSingle || fraction <= 0)
return m_start;
if (fraction >= 1)
return m_end;
if (m_start == EVisibility::kVisible || m_end == EVisibility::kVisible)
return EVisibility::kVisible;
return fraction < 0.5 ? m_start : m_end;
}
DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
private:
CSSVisibilityNonInterpolableValue(EVisibility start, EVisibility end)
: m_start(start), m_end(end), m_isSingle(m_start == m_end) {}
const EVisibility m_start;
const EVisibility m_end;
const bool m_isSingle;
};
DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSVisibilityNonInterpolableValue);
DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(CSSVisibilityNonInterpolableValue);
class UnderlyingVisibilityChecker
: public InterpolationType::ConversionChecker {
public:
~UnderlyingVisibilityChecker() final {}
static std::unique_ptr<UnderlyingVisibilityChecker> create(
EVisibility visibility) {
return WTF::wrapUnique(new UnderlyingVisibilityChecker(visibility));
}
private:
UnderlyingVisibilityChecker(EVisibility visibility)
: m_visibility(visibility) {}
bool isValid(const InterpolationEnvironment&,
const InterpolationValue& underlying) const final {
double underlyingFraction =
toInterpolableNumber(*underlying.interpolableValue).value();
EVisibility underlyingVisibility =
toCSSVisibilityNonInterpolableValue(*underlying.nonInterpolableValue)
.visibility(underlyingFraction);
return m_visibility == underlyingVisibility;
}
const EVisibility m_visibility;
};
class InheritedVisibilityChecker : public InterpolationType::ConversionChecker {
public:
static std::unique_ptr<InheritedVisibilityChecker> create(
EVisibility visibility) {
return WTF::wrapUnique(new InheritedVisibilityChecker(visibility));
}
private:
InheritedVisibilityChecker(EVisibility visibility)
: m_visibility(visibility) {}
bool isValid(const InterpolationEnvironment& environment,
const InterpolationValue& underlying) const final {
return m_visibility == environment.state().parentStyle()->visibility();
}
const EVisibility m_visibility;
};
InterpolationValue CSSVisibilityInterpolationType::createVisibilityValue(
EVisibility visibility) const {
return InterpolationValue(
InterpolableNumber::create(0),
CSSVisibilityNonInterpolableValue::create(visibility, visibility));
}
InterpolationValue CSSVisibilityInterpolationType::maybeConvertNeutral(
const InterpolationValue& underlying,
ConversionCheckers& conversionCheckers) const {
double underlyingFraction =
toInterpolableNumber(*underlying.interpolableValue).value();
EVisibility underlyingVisibility =
toCSSVisibilityNonInterpolableValue(*underlying.nonInterpolableValue)
.visibility(underlyingFraction);
conversionCheckers.push_back(
UnderlyingVisibilityChecker::create(underlyingVisibility));
return createVisibilityValue(underlyingVisibility);
}
InterpolationValue CSSVisibilityInterpolationType::maybeConvertInitial(
const StyleResolverState&,
ConversionCheckers&) const {
return createVisibilityValue(EVisibility::kVisible);
}
InterpolationValue CSSVisibilityInterpolationType::maybeConvertInherit(
const StyleResolverState& state,
ConversionCheckers& conversionCheckers) const {
if (!state.parentStyle())
return nullptr;
EVisibility inheritedVisibility = state.parentStyle()->visibility();
conversionCheckers.push_back(
InheritedVisibilityChecker::create(inheritedVisibility));
return createVisibilityValue(inheritedVisibility);
}
InterpolationValue CSSVisibilityInterpolationType::maybeConvertValue(
const CSSValue& value,
const StyleResolverState& state,
ConversionCheckers& conversionCheckers) const {
if (!value.isIdentifierValue())
return nullptr;
const CSSIdentifierValue& identifierValue = toCSSIdentifierValue(value);
CSSValueID keyword = identifierValue.getValueID();
switch (keyword) {
case CSSValueHidden:
case CSSValueVisible:
case CSSValueCollapse:
return createVisibilityValue(identifierValue.convertTo<EVisibility>());
default:
return nullptr;
}
}
InterpolationValue
CSSVisibilityInterpolationType::maybeConvertStandardPropertyUnderlyingValue(
const StyleResolverState& state) const {
return createVisibilityValue(state.style()->visibility());
}
PairwiseInterpolationValue CSSVisibilityInterpolationType::maybeMergeSingles(
InterpolationValue&& start,
InterpolationValue&& end) const {
return PairwiseInterpolationValue(
InterpolableNumber::create(0), InterpolableNumber::create(1),
CSSVisibilityNonInterpolableValue::create(
toCSSVisibilityNonInterpolableValue(*start.nonInterpolableValue)
.visibility(),
toCSSVisibilityNonInterpolableValue(*end.nonInterpolableValue)
.visibility()));
}
void CSSVisibilityInterpolationType::composite(
UnderlyingValueOwner& underlyingValueOwner,
double underlyingFraction,
const InterpolationValue& value,
double interpolationFraction) const {
underlyingValueOwner.set(*this, value);
}
void CSSVisibilityInterpolationType::applyStandardPropertyValue(
const InterpolableValue& interpolableValue,
const NonInterpolableValue* nonInterpolableValue,
StyleResolverState& state) const {
// Visibility interpolation has been deferred to application time here due to
// its non-linear behaviour.
double fraction = toInterpolableNumber(interpolableValue).value();
EVisibility visibility =
toCSSVisibilityNonInterpolableValue(nonInterpolableValue)
->visibility(fraction);
state.style()->setVisibility(visibility);
}
} // namespace blink