blob: 1b90cc2a1ab5efc1dae5c2224c2429eceb485e86 [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/LengthListPropertyFunctions.h"
#include "core/style/ComputedStyle.h"
namespace blink {
namespace {
const FillLayer* GetFillLayerForPosition(const CSSProperty& property,
const ComputedStyle& style) {
switch (property.PropertyID()) {
case CSSPropertyBackgroundPositionX:
case CSSPropertyBackgroundPositionY:
return &style.BackgroundLayers();
case CSSPropertyWebkitMaskPositionX:
case CSSPropertyWebkitMaskPositionY:
return &style.MaskLayers();
default:
NOTREACHED();
return nullptr;
}
}
FillLayer* AccessFillLayerForPosition(const CSSProperty& property,
ComputedStyle& style) {
switch (property.PropertyID()) {
case CSSPropertyBackgroundPositionX:
case CSSPropertyBackgroundPositionY:
return &style.AccessBackgroundLayers();
case CSSPropertyWebkitMaskPositionX:
case CSSPropertyWebkitMaskPositionY:
return &style.AccessMaskLayers();
default:
NOTREACHED();
return nullptr;
}
}
struct FillLayerMethods {
FillLayerMethods(const CSSProperty& property) {
switch (property.PropertyID()) {
case CSSPropertyBackgroundPositionX:
case CSSPropertyWebkitMaskPositionX:
is_set = &FillLayer::IsPositionXSet;
get_length = &FillLayer::PositionX;
get_edge = &FillLayer::BackgroundXOrigin;
set_length = &FillLayer::SetPositionX;
clear = &FillLayer::ClearPositionX;
break;
case CSSPropertyBackgroundPositionY:
case CSSPropertyWebkitMaskPositionY:
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 CSSPropertyBackgroundPositionX:
case CSSPropertyBackgroundPositionY:
case CSSPropertyObjectPosition:
case CSSPropertyOffsetAnchor:
case CSSPropertyOffsetPosition:
case CSSPropertyPerspectiveOrigin:
case CSSPropertyTransformOrigin:
case CSSPropertyWebkitMaskPositionX:
case CSSPropertyWebkitMaskPositionY:
return kValueRangeAll;
case CSSPropertyBorderBottomLeftRadius:
case CSSPropertyBorderBottomRightRadius:
case CSSPropertyBorderTopLeftRadius:
case CSSPropertyBorderTopRightRadius:
case CSSPropertyStrokeDasharray:
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(transform_origin.Z(), kFixed));
return true;
}
bool LengthListPropertyFunctions::GetLengthList(const CSSProperty& property,
const ComputedStyle& style,
Vector<Length>& result) {
DCHECK(result.IsEmpty());
switch (property.PropertyID()) {
case CSSPropertyStrokeDasharray: {
if (style.StrokeDashArray())
result.AppendVector(style.StrokeDashArray()->GetVector());
return true;
}
case CSSPropertyObjectPosition:
return AppendToVector(style.ObjectPosition(), result);
case CSSPropertyOffsetAnchor:
return AppendToVector(style.OffsetAnchor(), result);
case CSSPropertyOffsetPosition:
return AppendToVector(style.OffsetPosition(), result);
case CSSPropertyPerspectiveOrigin:
return AppendToVector(style.PerspectiveOrigin(), result);
case CSSPropertyBorderBottomLeftRadius:
return AppendToVector(style.BorderBottomLeftRadius(), result);
case CSSPropertyBorderBottomRightRadius:
return AppendToVector(style.BorderBottomRightRadius(), result);
case CSSPropertyBorderTopLeftRadius:
return AppendToVector(style.BorderTopLeftRadius(), result);
case CSSPropertyBorderTopRightRadius:
return AppendToVector(style.BorderTopRightRadius(), result);
case CSSPropertyTransformOrigin:
return AppendToVector(style.GetTransformOrigin(), result);
case CSSPropertyBackgroundPositionX:
case CSSPropertyBackgroundPositionY:
case CSSPropertyWebkitMaskPositionX:
case CSSPropertyWebkitMaskPositionY: {
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 CSSPropertyStrokeDasharray:
style.SetStrokeDashArray(
length_list.IsEmpty()
? nullptr
: RefVector<Length>::Create(std::move(length_list)));
return;
case CSSPropertyObjectPosition:
style.SetObjectPosition(PointFromVector(length_list));
return;
case CSSPropertyOffsetAnchor:
style.SetOffsetAnchor(PointFromVector(length_list));
return;
case CSSPropertyOffsetPosition:
style.SetOffsetPosition(PointFromVector(length_list));
return;
case CSSPropertyPerspectiveOrigin:
style.SetPerspectiveOrigin(PointFromVector(length_list));
return;
case CSSPropertyBorderBottomLeftRadius:
style.SetBorderBottomLeftRadius(SizeFromVector(length_list));
return;
case CSSPropertyBorderBottomRightRadius:
style.SetBorderBottomRightRadius(SizeFromVector(length_list));
return;
case CSSPropertyBorderTopLeftRadius:
style.SetBorderTopLeftRadius(SizeFromVector(length_list));
return;
case CSSPropertyBorderTopRightRadius:
style.SetBorderTopRightRadius(SizeFromVector(length_list));
return;
case CSSPropertyTransformOrigin:
style.SetTransformOrigin(TransformOriginFromVector(length_list));
return;
case CSSPropertyBackgroundPositionX:
case CSSPropertyBackgroundPositionY:
case CSSPropertyWebkitMaskPositionX:
case CSSPropertyWebkitMaskPositionY: {
FillLayer* fill_layer = AccessFillLayerForPosition(property, style);
FillLayer* prev = nullptr;
FillLayerMethods fill_layer_methods(property);
for (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