blob: e5214f4a609e958e76f9e5e076b3e7cd21c0adad [file] [log] [blame]
// Copyright 2016 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/basic_shape_interpolation_functions.h"
#include <memory>
#include "third_party/blink/renderer/core/animation/css_position_axis_list_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/interpolable_length.h"
#include "third_party/blink/renderer/core/css/css_basic_shape_values.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_math_function_value.h"
#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
#include "third_party/blink/renderer/core/style/basic_shapes.h"
namespace blink {
class BasicShapeNonInterpolableValue : public NonInterpolableValue {
public:
static scoped_refptr<const NonInterpolableValue> Create(
BasicShape::ShapeType type) {
return base::AdoptRef(new BasicShapeNonInterpolableValue(type));
}
static scoped_refptr<const NonInterpolableValue> CreatePolygon(
WindRule wind_rule,
wtf_size_t size) {
return base::AdoptRef(new BasicShapeNonInterpolableValue(wind_rule, size));
}
BasicShape::ShapeType GetShapeType() const { return type_; }
WindRule GetWindRule() const {
DCHECK_EQ(GetShapeType(), BasicShape::kBasicShapePolygonType);
return wind_rule_;
}
wtf_size_t size() const {
DCHECK_EQ(GetShapeType(), BasicShape::kBasicShapePolygonType);
return size_;
}
bool IsCompatibleWith(const BasicShapeNonInterpolableValue& other) const {
if (GetShapeType() != other.GetShapeType()) {
return false;
}
switch (GetShapeType()) {
case BasicShape::kBasicShapeCircleType:
case BasicShape::kBasicShapeEllipseType:
case BasicShape::kBasicShapeInsetType:
return true;
case BasicShape::kBasicShapePolygonType:
return GetWindRule() == other.GetWindRule() && size() == other.size();
default:
NOTREACHED();
return false;
}
}
DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
private:
BasicShapeNonInterpolableValue(BasicShape::ShapeType type)
: type_(type), wind_rule_(RULE_NONZERO), size_(0) {
DCHECK_NE(type, BasicShape::kBasicShapePolygonType);
}
BasicShapeNonInterpolableValue(WindRule wind_rule, wtf_size_t size)
: type_(BasicShape::kBasicShapePolygonType),
wind_rule_(wind_rule),
size_(size) {}
const BasicShape::ShapeType type_;
const WindRule wind_rule_;
const wtf_size_t size_;
};
DEFINE_NON_INTERPOLABLE_VALUE_TYPE(BasicShapeNonInterpolableValue);
template <>
struct DowncastTraits<BasicShapeNonInterpolableValue> {
static bool AllowFrom(const NonInterpolableValue* value) {
return value && AllowFrom(*value);
}
static bool AllowFrom(const NonInterpolableValue& value) {
return value.GetType() == BasicShapeNonInterpolableValue::static_type_;
}
};
namespace {
InterpolableValue* Unwrap(InterpolationValue&& value) {
DCHECK(value.interpolable_value);
return std::move(value.interpolable_value);
}
InterpolableValue* ConvertCSSCoordinate(const CSSValue* coordinate) {
if (coordinate) {
return Unwrap(
CSSPositionAxisListInterpolationType::ConvertPositionAxisCSSValue(
*coordinate));
}
return InterpolableLength::MaybeConvertLength(Length::Percent(50), 1);
}
InterpolableValue* ConvertCoordinate(
const BasicShapeCenterCoordinate& coordinate,
double zoom) {
return InterpolableLength::MaybeConvertLength(coordinate.ComputedLength(),
zoom);
}
InterpolableValue* CreateNeutralInterpolableCoordinate() {
return InterpolableLength::CreateNeutral();
}
BasicShapeCenterCoordinate CreateCoordinate(
const InterpolableValue& interpolable_value,
const CSSToLengthConversionData& conversion_data) {
return BasicShapeCenterCoordinate(
BasicShapeCenterCoordinate::kTopLeft,
To<InterpolableLength>(interpolable_value)
.CreateLength(conversion_data, Length::ValueRange::kAll));
}
InterpolableValue* ConvertCSSRadius(const CSSValue* radius) {
if (!radius || radius->IsIdentifierValue()) {
return nullptr;
}
return InterpolableLength::MaybeConvertCSSValue(*radius);
}
InterpolableValue* ConvertRadius(const BasicShapeRadius& radius, double zoom) {
if (radius.GetType() != BasicShapeRadius::kValue) {
return nullptr;
}
return InterpolableLength::MaybeConvertLength(radius.Value(), zoom);
}
InterpolableValue* CreateNeutralInterpolableRadius() {
return InterpolableLength::CreateNeutral();
}
BasicShapeRadius CreateRadius(
const InterpolableValue& interpolable_value,
const CSSToLengthConversionData& conversion_data) {
return BasicShapeRadius(
To<InterpolableLength>(interpolable_value)
.CreateLength(conversion_data, Length::ValueRange::kNonNegative));
}
InterpolableLength* ConvertCSSLength(const CSSValue& length) {
return InterpolableLength::MaybeConvertCSSValue(length);
}
InterpolableLength* ConvertCSSLength(const CSSValue* length) {
if (!length) {
return InterpolableLength::CreateNeutral();
}
return ConvertCSSLength(*length);
}
InterpolableLength* ConvertCSSLengthOrAuto(const CSSValue& length,
double auto_percent) {
auto* identifier = DynamicTo<CSSIdentifierValue>(length);
if (identifier && identifier->GetValueID() == CSSValueID::kAuto) {
return InterpolableLength::CreatePercent(auto_percent);
}
return InterpolableLength::MaybeConvertCSSValue(length);
}
const CSSMathExpressionNode* AsExpressionNode(const CSSPrimitiveValue& value) {
if (const auto* numeric_literal = DynamicTo<CSSNumericLiteralValue>(value)) {
return CSSMathExpressionNumericLiteral::Create(numeric_literal);
}
return To<CSSMathFunctionValue>(value).ExpressionNode();
}
// Generate the expression: calc(minuend - subtrahend).
const CSSMathExpressionNode* SubtractCSSLength(
const CSSMathExpressionNode& minuend,
const CSSPrimitiveValue& subtrahend) {
return CSSMathExpressionOperation::CreateArithmeticOperationSimplified(
&minuend, AsExpressionNode(subtrahend), CSSMathOperator::kSubtract);
}
// Produce a InterpolableLength from a CSSMathExpressionNode expression tree.
InterpolableLength* FinalizeExpression(
const CSSMathExpressionNode& difference) {
CSSLengthArray length_array;
if (difference.AccumulateLengthArray(length_array, 1)) {
return MakeGarbageCollected<InterpolableLength>(std::move(length_array));
}
return MakeGarbageCollected<InterpolableLength>(difference);
}
// Generate the expression: calc(100% - a - b).
InterpolableLength* ConvertCSSLengthsSubtractedFrom100Percent(
const CSSPrimitiveValue& a,
const CSSPrimitiveValue& b) {
const auto* percent_100 = CSSMathExpressionNumericLiteral::Create(
100, CSSPrimitiveValue::UnitType::kPercentage);
return FinalizeExpression(
*SubtractCSSLength(*SubtractCSSLength(*percent_100, a), b));
}
// Generate the expression: calc(100% - a).
InterpolableLength* ConvertCSSLengthSubtractedFrom100Percent(
const CSSPrimitiveValue& a) {
const auto* percent_100 = CSSMathExpressionNumericLiteral::Create(
100, CSSPrimitiveValue::UnitType::kPercentage);
return FinalizeExpression(*SubtractCSSLength(*percent_100, a));
}
InterpolableLength* ConvertCSSLengthOrAutoSubtractedFrom100Percent(
const CSSValue& length,
double auto_percent) {
auto* identifier = DynamicTo<CSSIdentifierValue>(length);
if (identifier && identifier->GetValueID() == CSSValueID::kAuto) {
return InterpolableLength::CreatePercent(auto_percent);
}
return ConvertCSSLengthSubtractedFrom100Percent(
To<CSSPrimitiveValue>(length));
}
InterpolableValue* ConvertLength(const Length& length, double zoom) {
return InterpolableLength::MaybeConvertLength(length, zoom);
}
InterpolableValue* ConvertCSSBorderRadiusWidth(const CSSValuePair* pair) {
return ConvertCSSLength(pair ? &pair->First() : nullptr);
}
InterpolableValue* ConvertCSSBorderRadiusHeight(const CSSValuePair* pair) {
return ConvertCSSLength(pair ? &pair->Second() : nullptr);
}
LengthSize CreateBorderRadius(
const InterpolableValue& width,
const InterpolableValue& height,
const CSSToLengthConversionData& conversion_data) {
return LengthSize(To<InterpolableLength>(width).CreateLength(
conversion_data, Length::ValueRange::kNonNegative),
To<InterpolableLength>(height).CreateLength(
conversion_data, Length::ValueRange::kNonNegative));
}
namespace circle_functions {
enum CircleComponentIndex : unsigned {
kCircleCenterXIndex,
kCircleCenterYIndex,
kCircleRadiusIndex,
kCircleHasExplicitCenterIndex,
kCircleComponentIndexCount,
};
InterpolationValue ConvertCSSValue(
const cssvalue::CSSBasicShapeCircleValue& circle) {
auto* list =
MakeGarbageCollected<InterpolableList>(kCircleComponentIndexCount);
list->Set(kCircleCenterXIndex, ConvertCSSCoordinate(circle.CenterX()));
list->Set(kCircleCenterYIndex, ConvertCSSCoordinate(circle.CenterY()));
list->Set(kCircleHasExplicitCenterIndex,
MakeGarbageCollected<InterpolableNumber>(!!circle.CenterX()));
InterpolableValue* radius = nullptr;
if (!(radius = ConvertCSSRadius(circle.Radius()))) {
return nullptr;
}
list->Set(kCircleRadiusIndex, radius);
return InterpolationValue(std::move(list),
BasicShapeNonInterpolableValue::Create(
BasicShape::kBasicShapeCircleType));
}
InterpolationValue ConvertBasicShape(const BasicShapeCircle& circle,
double zoom) {
auto* list =
MakeGarbageCollected<InterpolableList>(kCircleComponentIndexCount);
list->Set(kCircleCenterXIndex, ConvertCoordinate(circle.CenterX(), zoom));
list->Set(kCircleCenterYIndex, ConvertCoordinate(circle.CenterY(), zoom));
list->Set(
kCircleHasExplicitCenterIndex,
MakeGarbageCollected<InterpolableNumber>(circle.HasExplicitCenter()));
InterpolableValue* radius = nullptr;
if (!(radius = ConvertRadius(circle.Radius(), zoom))) {
return nullptr;
}
list->Set(kCircleRadiusIndex, radius);
return InterpolationValue(std::move(list),
BasicShapeNonInterpolableValue::Create(
BasicShape::kBasicShapeCircleType));
}
InterpolableValue* CreateNeutralValue() {
auto* list =
MakeGarbageCollected<InterpolableList>(kCircleComponentIndexCount);
list->Set(kCircleCenterXIndex, CreateNeutralInterpolableCoordinate());
list->Set(kCircleCenterYIndex, CreateNeutralInterpolableCoordinate());
list->Set(kCircleRadiusIndex, CreateNeutralInterpolableRadius());
list->Set(kCircleHasExplicitCenterIndex,
MakeGarbageCollected<InterpolableNumber>(0));
return list;
}
scoped_refptr<BasicShape> CreateBasicShape(
const InterpolableValue& interpolable_value,
const CSSToLengthConversionData& conversion_data) {
scoped_refptr<BasicShapeCircle> circle = BasicShapeCircle::Create();
const auto& list = To<InterpolableList>(interpolable_value);
circle->SetCenterX(
CreateCoordinate(*list.Get(kCircleCenterXIndex), conversion_data));
circle->SetCenterY(
CreateCoordinate(*list.Get(kCircleCenterYIndex), conversion_data));
circle->SetRadius(
CreateRadius(*list.Get(kCircleRadiusIndex), conversion_data));
circle->SetHasExplicitCenter(
To<InterpolableNumber>(list.Get(kCircleHasExplicitCenterIndex))
->Value(conversion_data));
return circle;
}
} // namespace circle_functions
namespace ellipse_functions {
enum EllipseComponentIndex : unsigned {
kEllipseCenterXIndex,
kEllipseCenterYIndex,
kEllipseRadiusXIndex,
kEllipseRadiusYIndex,
kEllipseHasExplicitCenter,
kEllipseComponentIndexCount,
};
InterpolationValue ConvertCSSValue(
const cssvalue::CSSBasicShapeEllipseValue& ellipse) {
auto* list =
MakeGarbageCollected<InterpolableList>(kEllipseComponentIndexCount);
list->Set(kEllipseCenterXIndex, ConvertCSSCoordinate(ellipse.CenterX()));
list->Set(kEllipseCenterYIndex, ConvertCSSCoordinate(ellipse.CenterY()));
list->Set(kEllipseHasExplicitCenter,
MakeGarbageCollected<InterpolableNumber>(!!ellipse.CenterX()));
InterpolableValue* radius = nullptr;
if (!(radius = ConvertCSSRadius(ellipse.RadiusX()))) {
return nullptr;
}
list->Set(kEllipseRadiusXIndex, radius);
if (!(radius = ConvertCSSRadius(ellipse.RadiusY()))) {
return nullptr;
}
list->Set(kEllipseRadiusYIndex, radius);
return InterpolationValue(list, BasicShapeNonInterpolableValue::Create(
BasicShape::kBasicShapeEllipseType));
}
InterpolationValue ConvertBasicShape(const BasicShapeEllipse& ellipse,
double zoom) {
auto* list =
MakeGarbageCollected<InterpolableList>(kEllipseComponentIndexCount);
list->Set(kEllipseCenterXIndex, ConvertCoordinate(ellipse.CenterX(), zoom));
list->Set(kEllipseCenterYIndex, ConvertCoordinate(ellipse.CenterY(), zoom));
list->Set(kEllipseHasExplicitCenter, MakeGarbageCollected<InterpolableNumber>(
ellipse.HasExplicitCenter()));
InterpolableValue* radius = nullptr;
if (!(radius = ConvertRadius(ellipse.RadiusX(), zoom))) {
return nullptr;
}
list->Set(kEllipseRadiusXIndex, radius);
if (!(radius = ConvertRadius(ellipse.RadiusY(), zoom))) {
return nullptr;
}
list->Set(kEllipseRadiusYIndex, radius);
return InterpolationValue(list, BasicShapeNonInterpolableValue::Create(
BasicShape::kBasicShapeEllipseType));
}
InterpolableValue* CreateNeutralValue() {
auto* list =
MakeGarbageCollected<InterpolableList>(kEllipseComponentIndexCount);
list->Set(kEllipseCenterXIndex, CreateNeutralInterpolableCoordinate());
list->Set(kEllipseCenterYIndex, CreateNeutralInterpolableCoordinate());
list->Set(kEllipseRadiusXIndex, CreateNeutralInterpolableRadius());
list->Set(kEllipseRadiusYIndex, CreateNeutralInterpolableRadius());
list->Set(kEllipseHasExplicitCenter,
MakeGarbageCollected<InterpolableNumber>(0));
return list;
}
scoped_refptr<BasicShape> CreateBasicShape(
const InterpolableValue& interpolable_value,
const CSSToLengthConversionData& conversion_data) {
scoped_refptr<BasicShapeEllipse> ellipse = BasicShapeEllipse::Create();
const auto& list = To<InterpolableList>(interpolable_value);
ellipse->SetCenterX(
CreateCoordinate(*list.Get(kEllipseCenterXIndex), conversion_data));
ellipse->SetCenterY(
CreateCoordinate(*list.Get(kEllipseCenterYIndex), conversion_data));
ellipse->SetRadiusX(
CreateRadius(*list.Get(kEllipseRadiusXIndex), conversion_data));
ellipse->SetRadiusY(
CreateRadius(*list.Get(kEllipseRadiusYIndex), conversion_data));
ellipse->SetHasExplicitCenter(
To<InterpolableNumber>(list.Get(kEllipseHasExplicitCenter))
->Value(conversion_data));
return ellipse;
}
} // namespace ellipse_functions
namespace inset_functions {
enum InsetComponentIndex : unsigned {
kInsetTopIndex,
kInsetRightIndex,
kInsetBottomIndex,
kInsetLeftIndex,
kInsetBorderTopLeftWidthIndex,
kInsetBorderTopLeftHeightIndex,
kInsetBorderTopRightWidthIndex,
kInsetBorderTopRightHeightIndex,
kInsetBorderBottomRightWidthIndex,
kInsetBorderBottomRightHeightIndex,
kInsetBorderBottomLeftWidthIndex,
kInsetBorderBottomLeftHeightIndex,
kInsetComponentIndexCount,
};
InterpolationValue ConvertCSSValue(
const cssvalue::CSSBasicShapeInsetValue& inset) {
auto* list =
MakeGarbageCollected<InterpolableList>(kInsetComponentIndexCount);
list->Set(kInsetTopIndex, ConvertCSSLength(inset.Top()));
list->Set(kInsetRightIndex, ConvertCSSLength(inset.Right()));
list->Set(kInsetBottomIndex, ConvertCSSLength(inset.Bottom()));
list->Set(kInsetLeftIndex, ConvertCSSLength(inset.Left()));
list->Set(kInsetBorderTopLeftWidthIndex,
ConvertCSSBorderRadiusWidth(inset.TopLeftRadius()));
list->Set(kInsetBorderTopLeftHeightIndex,
ConvertCSSBorderRadiusHeight(inset.TopLeftRadius()));
list->Set(kInsetBorderTopRightWidthIndex,
ConvertCSSBorderRadiusWidth(inset.TopRightRadius()));
list->Set(kInsetBorderTopRightHeightIndex,
ConvertCSSBorderRadiusHeight(inset.TopRightRadius()));
list->Set(kInsetBorderBottomRightWidthIndex,
ConvertCSSBorderRadiusWidth(inset.BottomRightRadius()));
list->Set(kInsetBorderBottomRightHeightIndex,
ConvertCSSBorderRadiusHeight(inset.BottomRightRadius()));
list->Set(kInsetBorderBottomLeftWidthIndex,
ConvertCSSBorderRadiusWidth(inset.BottomLeftRadius()));
list->Set(kInsetBorderBottomLeftHeightIndex,
ConvertCSSBorderRadiusHeight(inset.BottomLeftRadius()));
return InterpolationValue(list, BasicShapeNonInterpolableValue::Create(
BasicShape::kBasicShapeInsetType));
}
void FillCanonicalRect(InterpolableList* list,
const cssvalue::CSSBasicShapeRectValue& rect) {
// rect(t r b l) => inset(t calc(100% - r) calc(100% - b) l).
list->Set(kInsetTopIndex, ConvertCSSLengthOrAuto(*rect.Top(), 0));
list->Set(kInsetRightIndex,
ConvertCSSLengthOrAutoSubtractedFrom100Percent(*rect.Right(), 0));
list->Set(kInsetBottomIndex,
ConvertCSSLengthOrAutoSubtractedFrom100Percent(*rect.Bottom(), 0));
list->Set(kInsetLeftIndex, ConvertCSSLengthOrAuto(*rect.Left(), 0));
}
void FillCanonicalRect(InterpolableList* list,
const cssvalue::CSSBasicShapeXYWHValue& xywh) {
// xywh(x y w h) => inset(y calc(100% - (x + w)) calc(100% - (y + h)) x).
const CSSPrimitiveValue& x = *xywh.X();
const CSSPrimitiveValue& y = *xywh.Y();
const CSSPrimitiveValue& w = *xywh.Width();
const CSSPrimitiveValue& h = *xywh.Height();
list->Set(kInsetTopIndex, ConvertCSSLength(y));
// calc(100% - (x + w)) = calc(100% - x - w).
list->Set(kInsetRightIndex, ConvertCSSLengthsSubtractedFrom100Percent(x, w));
// calc(100% - (y + h)) = calc(100% - y - h).
list->Set(kInsetBottomIndex, ConvertCSSLengthsSubtractedFrom100Percent(y, h));
list->Set(kInsetLeftIndex, ConvertCSSLength(x));
}
template <typename BasicShapeCSSValueClass>
InterpolationValue ConvertCSSValueToInset(const BasicShapeCSSValueClass& rect) {
// Spec: All <basic-shape-rect> functions compute to the equivalent
// inset() function.
// NOTE: Given `xywh(x y w h)`, the equivalent function is `inset(y
// calc(100% - x - w) calc(100% - y - h) x)`. See:
// https://drafts.csswg.org/css-shapes/#basic-shape-computed-values and
// https://github.com/w3c/csswg-drafts/issues/9053
auto* list =
MakeGarbageCollected<InterpolableList>(kInsetComponentIndexCount);
FillCanonicalRect(list, rect);
list->Set(kInsetBorderTopLeftWidthIndex,
ConvertCSSBorderRadiusWidth(rect.TopLeftRadius()));
list->Set(kInsetBorderTopLeftHeightIndex,
ConvertCSSBorderRadiusHeight(rect.TopLeftRadius()));
list->Set(kInsetBorderTopRightWidthIndex,
ConvertCSSBorderRadiusWidth(rect.TopRightRadius()));
list->Set(kInsetBorderTopRightHeightIndex,
ConvertCSSBorderRadiusHeight(rect.TopRightRadius()));
list->Set(kInsetBorderBottomRightWidthIndex,
ConvertCSSBorderRadiusWidth(rect.BottomRightRadius()));
list->Set(kInsetBorderBottomRightHeightIndex,
ConvertCSSBorderRadiusHeight(rect.BottomRightRadius()));
list->Set(kInsetBorderBottomLeftWidthIndex,
ConvertCSSBorderRadiusWidth(rect.BottomLeftRadius()));
list->Set(kInsetBorderBottomLeftHeightIndex,
ConvertCSSBorderRadiusHeight(rect.BottomLeftRadius()));
return InterpolationValue(list, BasicShapeNonInterpolableValue::Create(
BasicShape::kBasicShapeInsetType));
}
InterpolationValue ConvertBasicShape(const BasicShapeInset& inset,
double zoom) {
auto* list =
MakeGarbageCollected<InterpolableList>(kInsetComponentIndexCount);
list->Set(kInsetTopIndex, ConvertLength(inset.Top(), zoom));
list->Set(kInsetRightIndex, ConvertLength(inset.Right(), zoom));
list->Set(kInsetBottomIndex, ConvertLength(inset.Bottom(), zoom));
list->Set(kInsetLeftIndex, ConvertLength(inset.Left(), zoom));
list->Set(kInsetBorderTopLeftWidthIndex,
ConvertLength(inset.TopLeftRadius().Width(), zoom));
list->Set(kInsetBorderTopLeftHeightIndex,
ConvertLength(inset.TopLeftRadius().Height(), zoom));
list->Set(kInsetBorderTopRightWidthIndex,
ConvertLength(inset.TopRightRadius().Width(), zoom));
list->Set(kInsetBorderTopRightHeightIndex,
ConvertLength(inset.TopRightRadius().Height(), zoom));
list->Set(kInsetBorderBottomRightWidthIndex,
ConvertLength(inset.BottomRightRadius().Width(), zoom));
list->Set(kInsetBorderBottomRightHeightIndex,
ConvertLength(inset.BottomRightRadius().Height(), zoom));
list->Set(kInsetBorderBottomLeftWidthIndex,
ConvertLength(inset.BottomLeftRadius().Width(), zoom));
list->Set(kInsetBorderBottomLeftHeightIndex,
ConvertLength(inset.BottomLeftRadius().Height(), zoom));
return InterpolationValue(list, BasicShapeNonInterpolableValue::Create(
BasicShape::kBasicShapeInsetType));
}
InterpolableValue* CreateNeutralValue() {
auto* list =
MakeGarbageCollected<InterpolableList>(kInsetComponentIndexCount);
list->Set(kInsetTopIndex, InterpolableLength::CreateNeutral());
list->Set(kInsetRightIndex, InterpolableLength::CreateNeutral());
list->Set(kInsetBottomIndex, InterpolableLength::CreateNeutral());
list->Set(kInsetLeftIndex, InterpolableLength::CreateNeutral());
list->Set(kInsetBorderTopLeftWidthIndex, InterpolableLength::CreateNeutral());
list->Set(kInsetBorderTopLeftHeightIndex,
InterpolableLength::CreateNeutral());
list->Set(kInsetBorderTopRightWidthIndex,
InterpolableLength::CreateNeutral());
list->Set(kInsetBorderTopRightHeightIndex,
InterpolableLength::CreateNeutral());
list->Set(kInsetBorderBottomRightWidthIndex,
InterpolableLength::CreateNeutral());
list->Set(kInsetBorderBottomRightHeightIndex,
InterpolableLength::CreateNeutral());
list->Set(kInsetBorderBottomLeftWidthIndex,
InterpolableLength::CreateNeutral());
list->Set(kInsetBorderBottomLeftHeightIndex,
InterpolableLength::CreateNeutral());
return list;
}
scoped_refptr<BasicShape> CreateBasicShape(
const InterpolableValue& interpolable_value,
const CSSToLengthConversionData& conversion_data) {
const auto& list = To<InterpolableList>(interpolable_value);
scoped_refptr<BasicShapeInset> inset = BasicShapeInset::Create();
inset->SetTop(To<InterpolableLength>(*list.Get(kInsetTopIndex))
.CreateLength(conversion_data, Length::ValueRange::kAll));
inset->SetRight(To<InterpolableLength>(*list.Get(kInsetRightIndex))
.CreateLength(conversion_data, Length::ValueRange::kAll));
inset->SetBottom(
To<InterpolableLength>(*list.Get(kInsetBottomIndex))
.CreateLength(conversion_data, Length::ValueRange::kAll));
inset->SetLeft(To<InterpolableLength>(*list.Get(kInsetLeftIndex))
.CreateLength(conversion_data, Length::ValueRange::kAll));
inset->SetTopLeftRadius(CreateBorderRadius(
*list.Get(kInsetBorderTopLeftWidthIndex),
*list.Get(kInsetBorderTopLeftHeightIndex), conversion_data));
inset->SetTopRightRadius(CreateBorderRadius(
*list.Get(kInsetBorderTopRightWidthIndex),
*list.Get(kInsetBorderTopRightHeightIndex), conversion_data));
inset->SetBottomRightRadius(CreateBorderRadius(
*list.Get(kInsetBorderBottomRightWidthIndex),
*list.Get(kInsetBorderBottomRightHeightIndex), conversion_data));
inset->SetBottomLeftRadius(CreateBorderRadius(
*list.Get(kInsetBorderBottomLeftWidthIndex),
*list.Get(kInsetBorderBottomLeftHeightIndex), conversion_data));
return inset;
}
} // namespace inset_functions
namespace polygon_functions {
InterpolationValue ConvertCSSValue(
const cssvalue::CSSBasicShapePolygonValue& polygon) {
wtf_size_t size = polygon.Values().size();
auto* list = MakeGarbageCollected<InterpolableList>(size);
for (wtf_size_t i = 0; i < size; i++) {
list->Set(i, ConvertCSSLength(polygon.Values()[i].Get()));
}
return InterpolationValue(list, BasicShapeNonInterpolableValue::CreatePolygon(
polygon.GetWindRule(), size));
}
InterpolationValue ConvertBasicShape(const BasicShapePolygon& polygon,
double zoom) {
wtf_size_t size = polygon.Values().size();
auto* list = MakeGarbageCollected<InterpolableList>(size);
for (wtf_size_t i = 0; i < size; i++) {
list->Set(i, ConvertLength(polygon.Values()[i], zoom));
}
return InterpolationValue(list, BasicShapeNonInterpolableValue::CreatePolygon(
polygon.GetWindRule(), size));
}
InterpolableValue* CreateNeutralValue(
const BasicShapeNonInterpolableValue& non_interpolable_value) {
auto* list =
MakeGarbageCollected<InterpolableList>(non_interpolable_value.size());
for (wtf_size_t i = 0; i < non_interpolable_value.size(); i++) {
list->Set(i, InterpolableLength::CreateNeutral());
}
return list;
}
scoped_refptr<BasicShape> CreateBasicShape(
const InterpolableValue& interpolable_value,
const BasicShapeNonInterpolableValue& non_interpolable_value,
const CSSToLengthConversionData& conversion_data) {
scoped_refptr<BasicShapePolygon> polygon = BasicShapePolygon::Create();
polygon->SetWindRule(non_interpolable_value.GetWindRule());
const auto& list = To<InterpolableList>(interpolable_value);
wtf_size_t size = non_interpolable_value.size();
DCHECK_EQ(list.length(), size);
DCHECK_EQ(size % 2, 0U);
for (wtf_size_t i = 0; i < size; i += 2) {
polygon->AppendPoint(
To<InterpolableLength>(*list.Get(i))
.CreateLength(conversion_data, Length::ValueRange::kAll),
To<InterpolableLength>(*list.Get(i + 1))
.CreateLength(conversion_data, Length::ValueRange::kAll));
}
return polygon;
}
} // namespace polygon_functions
} // namespace
InterpolationValue basic_shape_interpolation_functions::MaybeConvertCSSValue(
const CSSValue& value) {
if (auto* circle_value =
DynamicTo<cssvalue::CSSBasicShapeCircleValue>(value)) {
return circle_functions::ConvertCSSValue(*circle_value);
}
if (auto* ellipse_value =
DynamicTo<cssvalue::CSSBasicShapeEllipseValue>(value)) {
return ellipse_functions::ConvertCSSValue(*ellipse_value);
}
if (auto* inset_value = DynamicTo<cssvalue::CSSBasicShapeInsetValue>(value)) {
return inset_functions::ConvertCSSValue(*inset_value);
}
if (auto* rect_value = DynamicTo<cssvalue::CSSBasicShapeRectValue>(value)) {
return inset_functions::ConvertCSSValueToInset(*rect_value);
}
if (auto* xywh_value = DynamicTo<cssvalue::CSSBasicShapeXYWHValue>(value)) {
return inset_functions::ConvertCSSValueToInset(*xywh_value);
}
if (auto* polygon_value =
DynamicTo<cssvalue::CSSBasicShapePolygonValue>(value)) {
return polygon_functions::ConvertCSSValue(*polygon_value);
}
return nullptr;
}
InterpolationValue basic_shape_interpolation_functions::MaybeConvertBasicShape(
const BasicShape* shape,
double zoom) {
if (!shape) {
return nullptr;
}
switch (shape->GetType()) {
case BasicShape::kBasicShapeCircleType:
return circle_functions::ConvertBasicShape(To<BasicShapeCircle>(*shape),
zoom);
case BasicShape::kBasicShapeEllipseType:
return ellipse_functions::ConvertBasicShape(To<BasicShapeEllipse>(*shape),
zoom);
case BasicShape::kBasicShapeInsetType:
return inset_functions::ConvertBasicShape(To<BasicShapeInset>(*shape),
zoom);
case BasicShape::kBasicShapePolygonType:
return polygon_functions::ConvertBasicShape(To<BasicShapePolygon>(*shape),
zoom);
// Handled by PathInterpolationFunction.
case BasicShape::kStylePathType:
return nullptr;
default:
NOTREACHED();
return nullptr;
}
}
InterpolableValue* basic_shape_interpolation_functions::CreateNeutralValue(
const NonInterpolableValue& untyped_non_interpolable_value) {
const auto& non_interpolable_value =
To<BasicShapeNonInterpolableValue>(untyped_non_interpolable_value);
switch (non_interpolable_value.GetShapeType()) {
case BasicShape::kBasicShapeCircleType:
return circle_functions::CreateNeutralValue();
case BasicShape::kBasicShapeEllipseType:
return ellipse_functions::CreateNeutralValue();
case BasicShape::kBasicShapeInsetType:
return inset_functions::CreateNeutralValue();
case BasicShape::kBasicShapePolygonType:
return polygon_functions::CreateNeutralValue(non_interpolable_value);
default:
NOTREACHED();
return nullptr;
}
}
bool basic_shape_interpolation_functions::ShapesAreCompatible(
const NonInterpolableValue& a,
const NonInterpolableValue& b) {
return To<BasicShapeNonInterpolableValue>(a).IsCompatibleWith(
To<BasicShapeNonInterpolableValue>(b));
}
scoped_refptr<BasicShape> basic_shape_interpolation_functions::CreateBasicShape(
const InterpolableValue& interpolable_value,
const NonInterpolableValue& untyped_non_interpolable_value,
const CSSToLengthConversionData& conversion_data) {
const auto& non_interpolable_value =
To<BasicShapeNonInterpolableValue>(untyped_non_interpolable_value);
switch (non_interpolable_value.GetShapeType()) {
case BasicShape::kBasicShapeCircleType:
return circle_functions::CreateBasicShape(interpolable_value,
conversion_data);
case BasicShape::kBasicShapeEllipseType:
return ellipse_functions::CreateBasicShape(interpolable_value,
conversion_data);
case BasicShape::kBasicShapeInsetType:
return inset_functions::CreateBasicShape(interpolable_value,
conversion_data);
case BasicShape::kBasicShapePolygonType:
return polygon_functions::CreateBasicShape(
interpolable_value, non_interpolable_value, conversion_data);
default:
NOTREACHED();
return nullptr;
}
}
} // namespace blink