Skip to content

Commit

Permalink
Add interpolation type for custom <transform-function>
Browse files Browse the repository at this point in the history
Support animation of registered <transform-function> custom properties
via a new CSSCustomTransformFunctionInterpolationType.

The implementation currently supports interpolating between different
types of transform functions via a matrix based on the specification
saying that <transform-function> should also interpolate as the standard
transform property.

Bug: 911156
Change-Id: I983a54c0e799df77cfa89e8002a78c45b5cf16f9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4952484
Reviewed-by: Kevin Ellis <kevers@chromium.org>
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1215394}
  • Loading branch information
Rune Lillesveen authored and Chromium LUCI CQ committed Oct 26, 2023
1 parent 9772427 commit 1425147
Show file tree
Hide file tree
Showing 14 changed files with 485 additions and 240 deletions.
2 changes: 2 additions & 0 deletions third_party/blink/renderer/core/animation/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ blink_core_sources("animation") {
"css_custom_length_interpolation_type.h",
"css_custom_list_interpolation_type.cc",
"css_custom_list_interpolation_type.h",
"css_custom_transform_function_interpolation_type.cc",
"css_custom_transform_function_interpolation_type.h",
"css_custom_transform_interpolation_type.cc",
"css_custom_transform_interpolation_type.h",
"css_default_interpolation_type.cc",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/core/animation/css_custom_transform_function_interpolation_type.h"

#include "third_party/blink/renderer/core/animation/interpolable_transform_list.h"
#include "third_party/blink/renderer/core/css/properties/computed_style_utils.h"

namespace blink {

InterpolationValue
CSSCustomTransformFunctionInterpolationType::MaybeConvertNeutral(
const InterpolationValue& underlying,
ConversionCheckers&) const {
return InterpolationValue(std::make_unique<InterpolableTransformList>(
EmptyTransformOperations(),
TransformOperations::BoxSizeDependentMatrixBlending::kDisallow));
}

InterpolationValue
CSSCustomTransformFunctionInterpolationType::MaybeConvertValue(
const CSSValue& value,
const StyleResolverState*,
ConversionCheckers&) const {
auto* function_value = DynamicTo<CSSFunctionValue>(value);
if (!function_value || !IsTransformFunction(function_value->FunctionType())) {
return nullptr;
}

std::unique_ptr<InterpolableTransformList> interpolable =
InterpolableTransformList::ConvertCSSValue(
value, CSSToLengthConversionData(),
TransformOperations::BoxSizeDependentMatrixBlending::kDisallow);
CHECK_EQ(interpolable->operations().size(), 1u);
return InterpolationValue(std::move(interpolable));
}

const CSSValue* CSSCustomTransformFunctionInterpolationType::CreateCSSValue(
const InterpolableValue& value,
const NonInterpolableValue*,
const StyleResolverState&) const {
auto* list_value = DynamicTo<InterpolableTransformList>(value);
if (!list_value) {
return nullptr;
}
// The list of operations must be exactly 1. Otherwise we will have a CHECK
// failure inside ValueForTransformFunction().
return ComputedStyleUtils::ValueForTransformFunction(
list_value->operations());
}

InterpolationValue
CSSCustomTransformFunctionInterpolationType::PreInterpolationCompositeIfNeeded(
InterpolationValue value,
const InterpolationValue& underlying,
EffectModel::CompositeOperation composite,
ConversionCheckers& conversion_checkers) const {
if (composite == EffectModel::CompositeOperation::kCompositeAdd) {
// Transform interpolations will represent kCompositeAdd as separate
// transform function. For a single <transform-function>, fall back to
// accumulate to get a valid <tranform-function> value.
composite = EffectModel::CompositeOperation::kCompositeAccumulate;
}
return CSSTransformInterpolationType::PreInterpolationCompositeIfNeeded(
std::move(value), underlying, composite, conversion_checkers);
}

} // namespace blink
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CUSTOM_TRANSFORM_FUNCTION_INTERPOLATION_TYPE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CUSTOM_TRANSFORM_FUNCTION_INTERPOLATION_TYPE_H_

#include "base/notreached.h"
#include "third_party/blink/renderer/core/animation/css_transform_interpolation_type.h"

namespace blink {

// Interpolation type for registered property <transform-function> that is
// either not repeatable or repeatable with comma separation.
// <transform-function>+ can be interpolated as a <transform-list>.
class CSSCustomTransformFunctionInterpolationType
: public CSSTransformInterpolationType {
public:
CSSCustomTransformFunctionInterpolationType(
PropertyHandle property,
const PropertyRegistration* registration)
: CSSTransformInterpolationType(property, registration) {
CHECK(property.IsCSSCustomProperty());
}

InterpolationValue MaybeConvertNeutral(const InterpolationValue& underlying,
ConversionCheckers&) const final;
InterpolationValue MaybeConvertValue(const CSSValue&,
const StyleResolverState*,
ConversionCheckers&) const final;

const CSSValue* CreateCSSValue(const InterpolableValue&,
const NonInterpolableValue*,
const StyleResolverState&) const final;

private:
InterpolationValue PreInterpolationCompositeIfNeeded(
InterpolationValue value,
const InterpolationValue& underlying,
EffectModel::CompositeOperation,
ConversionCheckers&) const final;

// These methods only apply to CSSInterpolationTypes used by standard CSS
// properties.
// CSSCustomTransformInterpolationType is only accessible via registered
// custom CSS properties.
InterpolationValue MaybeConvertStandardPropertyUnderlyingValue(
const ComputedStyle&) const final {
NOTREACHED();
return nullptr;
}
void ApplyStandardPropertyValue(const InterpolableValue&,
const NonInterpolableValue*,
StyleResolverState&) const final {
NOTREACHED();
}
InterpolationValue MaybeConvertInitial(const StyleResolverState&,
ConversionCheckers&) const final {
NOTREACHED();
return nullptr;
}
InterpolationValue MaybeConvertInherit(const StyleResolverState&,
ConversionCheckers&) const final {
NOTREACHED();
return nullptr;
}
};

} // namespace blink

#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CUSTOM_TRANSFORM_FUNCTION_INTERPOLATION_TYPE_H_
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "third_party/blink/renderer/core/animation/css_content_visibility_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_custom_length_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_custom_list_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_custom_transform_function_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_custom_transform_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_default_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_display_interpolation_type.h"
Expand Down Expand Up @@ -474,10 +475,10 @@ size_t CSSInterpolationTypesMap::Version() const {
}

static std::unique_ptr<CSSInterpolationType>
CreateInterpolationTypeForCSSSyntax(CSSSyntaxType syntax,
CreateInterpolationTypeForCSSSyntax(const CSSSyntaxComponent syntax,
PropertyHandle property,
const PropertyRegistration& registration) {
switch (syntax) {
switch (syntax.GetType()) {
case CSSSyntaxType::kAngle:
return std::make_unique<CSSAngleInterpolationType>(property,
&registration);
Expand Down Expand Up @@ -509,8 +510,15 @@ CreateInterpolationTypeForCSSSyntax(CSSSyntaxType syntax,
return std::make_unique<CSSNumberInterpolationType>(property,
&registration, true);
case CSSSyntaxType::kTransformFunction:
// TODO(futhark): Implement smooth interpolation for <transform-function>
return nullptr;
if (!syntax.IsRepeatable() ||
syntax.GetRepeat() == CSSSyntaxRepeat::kCommaSeparated) {
// <transform-function> needs an interpolation type different from
// <transform-function>+ and <transform-list> as it can only use a
// single function representation for interpolation and composition.
return std::make_unique<CSSCustomTransformFunctionInterpolationType>(
property, &registration);
}
[[fallthrough]];
case CSSSyntaxType::kTransformList:
return std::make_unique<CSSCustomTransformInterpolationType>(
property, &registration);
Expand Down Expand Up @@ -540,13 +548,14 @@ CSSInterpolationTypesMap::CreateInterpolationTypesForCSSSyntax(

for (const CSSSyntaxComponent& component : definition.Components()) {
std::unique_ptr<CSSInterpolationType> interpolation_type =
CreateInterpolationTypeForCSSSyntax(component.GetType(), property,
registration);
CreateInterpolationTypeForCSSSyntax(component, property, registration);

if (!interpolation_type)
continue;

if (component.IsRepeatable()) {
if (component.IsRepeatable() &&
(component.GetType() != CSSSyntaxType::kTransformFunction ||
component.GetRepeat() != CSSSyntaxRepeat::kSpaceSeparated)) {
interpolation_type = std::make_unique<CSSCustomListInterpolationType>(
property, &registration, std::move(interpolation_type),
component.GetType(), component.GetRepeat());
Expand Down

0 comments on commit 1425147

Please sign in to comment.