blob: 69d5a13fd8d3f3c7a1026ea572c5f58c725f3498 [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 "third_party/blink/renderer/core/animation/length_list_property_functions.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
namespace {
const FillLayer* GetFillLayerForPosition(const CSSProperty& property,
const ComputedStyle& style) {
switch (property.PropertyID()) {
case CSSPropertyID::kBackgroundPositionX:
case CSSPropertyID::kBackgroundPositionY:
return &style.BackgroundLayers();
case CSSPropertyID::kWebkitMaskPositionX:
case CSSPropertyID::kWebkitMaskPositionY:
return &style.MaskLayers();
default:
NOTREACHED();
return nullptr;
}
}
FillLayer* AccessFillLayerForPosition(const CSSProperty& property,
ComputedStyle& style) {
switch (property.PropertyID()) {
case CSSPropertyID::kBackgroundPositionX:
case CSSPropertyID::kBackgroundPositionY:
return &style.AccessBackgroundLayers();
case CSSPropertyID::kWebkitMaskPositionX:
case CSSPropertyID::kWebkitMaskPositionY:
return &style.AccessMaskLayers();
default:
NOTREACHED();
return nullptr;
}
}
struct FillLayerMethods {
FillLayerMethods(const CSSProperty& property) {
switch (property.PropertyID()) {
case CSSPropertyID::kBackgroundPositionX:
case CSSPropertyID::kWebkitMaskPositionX:
is_set = &FillLayer::IsPositionXSet;
get_length = &FillLayer::PositionX;
get_edge = &FillLayer::BackgroundXOrigin;
set_length = &FillLayer::SetPositionX;
clear = &FillLayer::ClearPositionX;
break;
case CSSPropertyID::kBackgroundPositionY:
case CSSPropertyID::kWebkitMaskPositionY:
is_set = &FillLayer::IsPositionYSet;
get_length = &FillLayer::PositionY;
get_edge = &FillLayer::BackgroundYOrigin;
set_length = &FillLayer::SetPositionY;
clear = &FillLayer::ClearPositionY;
break;
default:
NOTREACHED();
break;
}
}
bool (FillLayer::*is_set)() const = nullptr;
const Length& (FillLayer::*get_length)() const = nullptr;
BackgroundEdgeOrigin (FillLayer::*get_edge)() const = nullptr;
void (FillLayer::*set_length)(const Length&) = nullptr;
void (FillLayer::*clear)() = nullptr;
};
} // namespace
ValueRange LengthListPropertyFunctions::GetValueRange(
const CSSProperty& property) {
switch (property.PropertyID()) {
case CSSPropertyID::kBackgroundPositionX:
case CSSPropertyID::kBackgroundPositionY:
case CSSPropertyID::kObjectPosition:
case CSSPropertyID::kOffsetAnchor:
case CSSPropertyID::kOffsetPosition:
case CSSPropertyID::kPerspectiveOrigin:
case CSSPropertyID::kTransformOrigin:
case CSSPropertyID::kWebkitMaskPositionX:
case CSSPropertyID::kWebkitMaskPositionY:
return kValueRangeAll;
case CSSPropertyID::kBorderBottomLeftRadius:
case CSSPropertyID::kBorderBottomRightRadius:
case CSSPropertyID::kBorderTopLeftRadius:
case CSSPropertyID::kBorderTopRightRadius:
case CSSPropertyID::kStrokeDasharray:
case CSSPropertyID::kContainIntrinsicSize:
return kValueRangeNonNegative;
default:
NOTREACHED();
return kValueRangeAll;
}
}
bool LengthListPropertyFunctions::GetInitialLengthList(
const CSSProperty& property,
Vector<Length>& result) {
return GetLengthList(property, ComputedStyle::InitialStyle(), result);
}
static bool AppendToVector(const LengthPoint& point, Vector<Length>& result) {
result.push_back(point.X());
result.push_back(point.Y());
return true;
}
static bool AppendToVector(const LengthSize& size, Vector<Length>& result) {
result.push_back(size.Width());
result.push_back(size.Height());
return true;
}
static bool AppendToVector(const TransformOrigin& transform_origin,
Vector<Length>& result) {
result.push_back(transform_origin.X());
result.push_back(transform_origin.Y());
result.push_back(Length::Fixed(transform_origin.Z()));
return true;
}
bool LengthListPropertyFunctions::GetLengthList(const CSSProperty& property,
const ComputedStyle& style,
Vector<Length>& result) {
DCHECK(result.IsEmpty());
switch (property.PropertyID()) {
case CSSPropertyID::kStrokeDasharray: {
if (style.StrokeDashArray())
result.AppendVector(style.StrokeDashArray()->data);
return true;
}
case CSSPropertyID::kObjectPosition:
return AppendToVector(style.ObjectPosition(), result);
case CSSPropertyID::kOffsetAnchor:
return AppendToVector(style.OffsetAnchor(), result);
case CSSPropertyID::kOffsetPosition:
return AppendToVector(style.OffsetPosition(), result);
case CSSPropertyID::kPerspectiveOrigin:
return AppendToVector(style.PerspectiveOrigin(), result);
case CSSPropertyID::kBorderBottomLeftRadius:
return AppendToVector(style.BorderBottomLeftRadius(), result);
case CSSPropertyID::kBorderBottomRightRadius:
return AppendToVector(style.BorderBottomRightRadius(), result);
case CSSPropertyID::kBorderTopLeftRadius:
return AppendToVector(style.BorderTopLeftRadius(), result);
case CSSPropertyID::kBorderTopRightRadius:
return AppendToVector(style.BorderTopRightRadius(), result);
case CSSPropertyID::kTransformOrigin:
return AppendToVector(style.GetTransformOrigin(), result);
case CSSPropertyID::kContainIntrinsicSize:
return AppendToVector(style.ContainIntrinsicSize(), result);
case CSSPropertyID::kBackgroundPositionX:
case CSSPropertyID::kBackgroundPositionY:
case CSSPropertyID::kWebkitMaskPositionX:
case CSSPropertyID::kWebkitMaskPositionY: {
const FillLayer* fill_layer = GetFillLayerForPosition(property, style);
FillLayerMethods fill_layer_methods(property);
while (fill_layer && (fill_layer->*fill_layer_methods.is_set)()) {
result.push_back((fill_layer->*fill_layer_methods.get_length)());
switch ((fill_layer->*fill_layer_methods.get_edge)()) {
case BackgroundEdgeOrigin::kRight:
case BackgroundEdgeOrigin::kBottom:
result.back() = result.back().SubtractFromOneHundredPercent();
break;
default:
break;
}
fill_layer = fill_layer->Next();
}
return true;
}
default:
NOTREACHED();
return false;
}
}
static LengthPoint PointFromVector(const Vector<Length>& list) {
DCHECK_EQ(list.size(), 2U);
return LengthPoint(list[0], list[1]);
}
static LengthSize SizeFromVector(const Vector<Length>& list) {
DCHECK_EQ(list.size(), 2U);
return LengthSize(list[0], list[1]);
}
static TransformOrigin TransformOriginFromVector(const Vector<Length>& list) {
DCHECK_EQ(list.size(), 3U);
return TransformOrigin(list[0], list[1], list[2].Pixels());
}
void LengthListPropertyFunctions::SetLengthList(const CSSProperty& property,
ComputedStyle& style,
Vector<Length>&& length_list) {
switch (property.PropertyID()) {
case CSSPropertyID::kStrokeDasharray:
style.SetStrokeDashArray(
length_list.IsEmpty()
? nullptr
: base::MakeRefCounted<SVGDashArray>(std::move(length_list)));
return;
case CSSPropertyID::kObjectPosition:
style.SetObjectPosition(PointFromVector(length_list));
return;
case CSSPropertyID::kOffsetAnchor:
style.SetOffsetAnchor(PointFromVector(length_list));
return;
case CSSPropertyID::kOffsetPosition:
style.SetOffsetPosition(PointFromVector(length_list));
return;
case CSSPropertyID::kPerspectiveOrigin:
style.SetPerspectiveOrigin(PointFromVector(length_list));
return;
case CSSPropertyID::kBorderBottomLeftRadius:
style.SetBorderBottomLeftRadius(SizeFromVector(length_list));
return;
case CSSPropertyID::kBorderBottomRightRadius:
style.SetBorderBottomRightRadius(SizeFromVector(length_list));
return;
case CSSPropertyID::kBorderTopLeftRadius:
style.SetBorderTopLeftRadius(SizeFromVector(length_list));
return;
case CSSPropertyID::kBorderTopRightRadius:
style.SetBorderTopRightRadius(SizeFromVector(length_list));
return;
case CSSPropertyID::kContainIntrinsicSize:
style.SetContainIntrinsicSize(SizeFromVector(length_list));
return;
case CSSPropertyID::kTransformOrigin:
style.SetTransformOrigin(TransformOriginFromVector(length_list));
return;
case CSSPropertyID::kBackgroundPositionX:
case CSSPropertyID::kBackgroundPositionY:
case CSSPropertyID::kWebkitMaskPositionX:
case CSSPropertyID::kWebkitMaskPositionY: {
FillLayer* fill_layer = AccessFillLayerForPosition(property, style);
FillLayer* prev = nullptr;
FillLayerMethods fill_layer_methods(property);
for (wtf_size_t i = 0; i < length_list.size(); i++) {
if (!fill_layer)
fill_layer = prev->EnsureNext();
(fill_layer->*fill_layer_methods.set_length)(length_list[i]);
prev = fill_layer;
fill_layer = fill_layer->Next();
}
while (fill_layer) {
(fill_layer->*fill_layer_methods.clear)();
fill_layer = fill_layer->Next();
}
return;
}
default:
NOTREACHED();
break;
}
}
} // namespace blink