mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-13 04:52:23 +00:00
LibWeb: Parse easing values manually
The values aren't that complex, so it doesn't make much sense to have a dedicated generator for them. Parsing them manually also allows us to have much more control over the produced values, so as a result of this change, EasingStyleValue becomes much more ergonomic.
This commit is contained in:
parent
6675ef3f24
commit
667e313731
Notes:
sideshowbarker
2024-07-16 22:51:10 +09:00
Author: https://github.com/mattco98
Commit: 667e313731
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/173
9 changed files with 405 additions and 192 deletions
|
@ -13,33 +13,105 @@
|
|||
|
||||
namespace Web::CSS {
|
||||
|
||||
// NOTE: Magic cubic bezier values from https://www.w3.org/TR/css-easing-1/#valdef-cubic-bezier-easing-function-ease
|
||||
|
||||
EasingStyleValue::CubicBezier EasingStyleValue::CubicBezier::ease()
|
||||
{
|
||||
static CubicBezier bezier { 0.25, 0.1, 0.25, 1.0 };
|
||||
return bezier;
|
||||
}
|
||||
|
||||
EasingStyleValue::CubicBezier EasingStyleValue::CubicBezier::ease_in()
|
||||
{
|
||||
static CubicBezier bezier { 0.42, 0.0, 1.0, 1.0 };
|
||||
return bezier;
|
||||
}
|
||||
|
||||
EasingStyleValue::CubicBezier EasingStyleValue::CubicBezier::ease_out()
|
||||
{
|
||||
static CubicBezier bezier { 0.0, 0.0, 0.58, 1.0 };
|
||||
return bezier;
|
||||
}
|
||||
|
||||
EasingStyleValue::CubicBezier EasingStyleValue::CubicBezier::ease_in_out()
|
||||
{
|
||||
static CubicBezier bezier { 0.42, 0.0, 0.58, 1.0 };
|
||||
return bezier;
|
||||
}
|
||||
|
||||
EasingStyleValue::Steps EasingStyleValue::Steps::step_start() {
|
||||
static Steps steps { 1, Steps::Position::Start };
|
||||
return steps;
|
||||
}
|
||||
|
||||
EasingStyleValue::Steps EasingStyleValue::Steps::step_end() {
|
||||
static Steps steps { 1, Steps::Position::End };
|
||||
return steps;
|
||||
}
|
||||
|
||||
String EasingStyleValue::to_string() const
|
||||
{
|
||||
if (m_properties.easing_function == EasingFunction::StepStart)
|
||||
return "steps(1, start)"_string;
|
||||
if (m_properties.easing_function == EasingFunction::StepEnd)
|
||||
return "steps(1, end)"_string;
|
||||
|
||||
StringBuilder builder;
|
||||
builder.append(CSS::to_string(m_properties.easing_function));
|
||||
m_function.visit(
|
||||
[&](Linear const& linear) {
|
||||
builder.append("linear"sv);
|
||||
if (!linear.stops.is_empty()) {
|
||||
builder.append('(');
|
||||
|
||||
if (m_properties.values.is_empty())
|
||||
return MUST(builder.to_string());
|
||||
|
||||
builder.append('(');
|
||||
for (size_t i = 0; i < m_properties.values.size(); ++i) {
|
||||
builder.append(m_properties.values[i]->to_string());
|
||||
if (i != m_properties.values.size() - 1)
|
||||
builder.append(", "sv);
|
||||
}
|
||||
builder.append(')');
|
||||
bool first = true;
|
||||
for (auto const& stop : linear.stops) {
|
||||
if (!first)
|
||||
builder.append(", "sv);
|
||||
first = false;
|
||||
builder.appendff("{}"sv, stop.offset);
|
||||
if (stop.position.has_value())
|
||||
builder.appendff(" {}"sv, stop.position.value());
|
||||
}
|
||||
|
||||
builder.append(')');
|
||||
}
|
||||
},
|
||||
[&](CubicBezier const& bezier) {
|
||||
if (bezier == CubicBezier::ease()) {
|
||||
builder.append("ease"sv);
|
||||
} else if (bezier == CubicBezier::ease_in()) {
|
||||
builder.append("ease-in"sv);
|
||||
} else if (bezier == CubicBezier::ease_out()) {
|
||||
builder.append("ease-out"sv);
|
||||
} else if (bezier == CubicBezier::ease_in_out()) {
|
||||
builder.append("ease-in-out"sv);
|
||||
} else {
|
||||
builder.appendff("cubic-bezier({}, {}, {}, {})", bezier.x1, bezier.y1, bezier.x2, bezier.y2);
|
||||
}
|
||||
},
|
||||
[&](Steps const& steps) {
|
||||
if (steps == Steps::step_start()) {
|
||||
builder.append("step-start"sv);
|
||||
} else if (steps == Steps::step_end()) {
|
||||
builder.append("step-end"sv);
|
||||
} else {
|
||||
auto position = [&] -> Optional<StringView> {
|
||||
switch (steps.position) {
|
||||
case Steps::Position::JumpStart:
|
||||
return "jump-start"sv;
|
||||
case Steps::Position::JumpNone:
|
||||
return "jump-none"sv;
|
||||
case Steps::Position::JumpBoth:
|
||||
return "jump-both"sv;
|
||||
case Steps::Position::Start:
|
||||
return "start"sv;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}();
|
||||
if (position.has_value()) {
|
||||
builder.appendff("steps({}, {})", steps.number_of_intervals, position.value());
|
||||
} else {
|
||||
builder.appendff("steps({})", steps.number_of_intervals);
|
||||
}
|
||||
}
|
||||
});
|
||||
return MUST(builder.to_string());
|
||||
}
|
||||
|
||||
bool EasingStyleValue::Properties::operator==(Properties const& other) const
|
||||
{
|
||||
return easing_function == other.easing_function && values == other.values;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,38 +10,80 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/CSS/EasingFunctions.h>
|
||||
#include <LibWeb/CSS/StyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class EasingStyleValue final : public StyleValueWithDefaultOperators<EasingStyleValue> {
|
||||
public:
|
||||
static ValueComparingNonnullRefPtr<EasingStyleValue> create(CSS::EasingFunction easing_function, StyleValueVector&& values)
|
||||
struct Linear {
|
||||
struct Stop {
|
||||
double offset;
|
||||
Optional<double> position;
|
||||
|
||||
bool operator==(Stop const&) const = default;
|
||||
};
|
||||
|
||||
Vector<Stop> stops;
|
||||
|
||||
bool operator==(Linear const&) const = default;
|
||||
};
|
||||
|
||||
struct CubicBezier {
|
||||
static CubicBezier ease();
|
||||
static CubicBezier ease_in();
|
||||
static CubicBezier ease_out();
|
||||
static CubicBezier ease_in_out();
|
||||
|
||||
double x1;
|
||||
double y1;
|
||||
double x2;
|
||||
double y2;
|
||||
|
||||
bool operator==(CubicBezier const&) const = default;
|
||||
};
|
||||
|
||||
struct Steps {
|
||||
enum class Position {
|
||||
JumpStart,
|
||||
JumpEnd,
|
||||
JumpNone,
|
||||
JumpBoth,
|
||||
Start,
|
||||
End,
|
||||
};
|
||||
|
||||
static Steps step_start();
|
||||
static Steps step_end();
|
||||
|
||||
unsigned int number_of_intervals;
|
||||
Position position { Position::End };
|
||||
|
||||
bool operator==(Steps const&) const = default;
|
||||
};
|
||||
|
||||
using Function = Variant<Linear, CubicBezier, Steps>;
|
||||
|
||||
static ValueComparingNonnullRefPtr<EasingStyleValue> create(Function const& function)
|
||||
{
|
||||
return adopt_ref(*new (nothrow) EasingStyleValue(easing_function, move(values)));
|
||||
return adopt_ref(*new (nothrow) EasingStyleValue(function));
|
||||
}
|
||||
virtual ~EasingStyleValue() override = default;
|
||||
|
||||
CSS::EasingFunction easing_function() const { return m_properties.easing_function; }
|
||||
StyleValueVector values() const { return m_properties.values; }
|
||||
Function const& function() const { return m_function; }
|
||||
|
||||
virtual String to_string() const override;
|
||||
|
||||
bool properties_equal(EasingStyleValue const& other) const { return m_properties == other.m_properties; }
|
||||
bool properties_equal(EasingStyleValue const& other) const { return m_function == other.m_function; }
|
||||
|
||||
private:
|
||||
EasingStyleValue(CSS::EasingFunction easing_function, StyleValueVector&& values)
|
||||
EasingStyleValue(Function function)
|
||||
: StyleValueWithDefaultOperators(Type::Easing)
|
||||
, m_properties { .easing_function = easing_function, .values = move(values) }
|
||||
, m_function(function)
|
||||
{
|
||||
}
|
||||
|
||||
struct Properties {
|
||||
CSS::EasingFunction easing_function;
|
||||
StyleValueVector values;
|
||||
bool operator==(Properties const& other) const;
|
||||
} m_properties;
|
||||
Function m_function;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue