mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 16:07:35 +00:00
LibWeb: Implement CSS Time class
This corresponds to `<time>` in the grammar.
This commit is contained in:
parent
0465abcfec
commit
608bfac2a9
9 changed files with 268 additions and 5 deletions
|
@ -55,6 +55,7 @@ set(SOURCES
|
|||
CSS/StyleValue.cpp
|
||||
CSS/Supports.cpp
|
||||
CSS/SyntaxHighlighter/SyntaxHighlighter.cpp
|
||||
CSS/Time.cpp
|
||||
CSS/ValueID.cpp
|
||||
CSS/ValueID.h
|
||||
Cookie/ParsedCookie.cpp
|
||||
|
|
|
@ -4310,6 +4310,8 @@ Optional<CalculatedStyleValue::CalcValue> Parser::parse_calc_value(TokenStream<S
|
|||
// Resolution is not allowed in calc()
|
||||
return {};
|
||||
}
|
||||
if (dimension.is_time())
|
||||
return CalculatedStyleValue::CalcValue { dimension.time() };
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,4 +24,9 @@ Length LengthPercentage::resolve_calculated(NonnullRefPtr<CalculatedStyleValue>
|
|||
return calculated->resolve_length_percentage(layout_node, reference_value)->resolved(layout_node, reference_value);
|
||||
}
|
||||
|
||||
Time TimePercentage::resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const& calculated, Layout::Node const& layout_node, Time const& reference_value) const
|
||||
{
|
||||
return calculated->resolve_time_percentage(reference_value)->resolved(layout_node, reference_value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <LibWeb/CSS/Angle.h>
|
||||
#include <LibWeb/CSS/Frequency.h>
|
||||
#include <LibWeb/CSS/Length.h>
|
||||
#include <LibWeb/CSS/Time.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
|
@ -180,6 +181,15 @@ public:
|
|||
virtual Length resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const&, Layout::Node const&, Length const& reference_value) const override;
|
||||
};
|
||||
|
||||
class TimePercentage : public PercentageOr<Time> {
|
||||
public:
|
||||
using PercentageOr<Time>::PercentageOr;
|
||||
|
||||
bool is_time() const { return is_t(); }
|
||||
Time const& time() const { return get_t(); }
|
||||
virtual Time resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const&, Layout::Node const&, Time const& reference_value) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -213,3 +223,11 @@ struct AK::Formatter<Web::CSS::LengthPercentage> : Formatter<StringView> {
|
|||
return Formatter<StringView>::format(builder, length_percentage.to_string());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AK::Formatter<Web::CSS::TimePercentage> : Formatter<StringView> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, Web::CSS::TimePercentage const& time_percentage)
|
||||
{
|
||||
return Formatter<StringView>::format(builder, time_percentage.to_string());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -183,6 +183,12 @@ TextDecorationStyleValue const& StyleValue::as_text_decoration() const
|
|||
return static_cast<TextDecorationStyleValue const&>(*this);
|
||||
}
|
||||
|
||||
TimeStyleValue const& StyleValue::as_time() const
|
||||
{
|
||||
VERIFY(is_time());
|
||||
return static_cast<TimeStyleValue const&>(*this);
|
||||
}
|
||||
|
||||
TransformationStyleValue const& StyleValue::as_transformation() const
|
||||
{
|
||||
VERIFY(is_transformation());
|
||||
|
@ -381,6 +387,24 @@ void CalculatedStyleValue::CalculationResult::add_or_subtract_internal(SumOperat
|
|||
m_value = Length::make_px(this_px - other_px);
|
||||
}
|
||||
},
|
||||
[&](Time const& time) {
|
||||
auto this_seconds = time.to_seconds();
|
||||
if (other.m_value.has<Time>()) {
|
||||
auto other_seconds = other.m_value.get<Time>().to_seconds();
|
||||
if (op == SumOperation::Add)
|
||||
m_value = Time::make_seconds(this_seconds + other_seconds);
|
||||
else
|
||||
m_value = Time::make_seconds(this_seconds - other_seconds);
|
||||
} else {
|
||||
VERIFY(percentage_basis.has<Time>());
|
||||
|
||||
auto other_seconds = percentage_basis.get<Time>().percentage_of(other.m_value.get<Percentage>()).to_seconds();
|
||||
if (op == SumOperation::Add)
|
||||
m_value = Time::make_seconds(this_seconds + other_seconds);
|
||||
else
|
||||
m_value = Time::make_seconds(this_seconds - other_seconds);
|
||||
}
|
||||
},
|
||||
[&](Percentage const& percentage) {
|
||||
if (other.m_value.has<Percentage>()) {
|
||||
if (op == SumOperation::Add)
|
||||
|
@ -433,6 +457,9 @@ void CalculatedStyleValue::CalculationResult::multiply_by(CalculationResult cons
|
|||
VERIFY(layout_node);
|
||||
m_value = Length::make_px(length.to_px(*layout_node) * other.m_value.get<Number>().value);
|
||||
},
|
||||
[&](Time const& time) {
|
||||
m_value = Time::make_seconds(time.to_seconds() * other.m_value.get<Number>().value);
|
||||
},
|
||||
[&](Percentage const& percentage) {
|
||||
m_value = Percentage { percentage.value() * other.m_value.get<Number>().value };
|
||||
});
|
||||
|
@ -463,6 +490,9 @@ void CalculatedStyleValue::CalculationResult::divide_by(CalculationResult const&
|
|||
VERIFY(layout_node);
|
||||
m_value = Length::make_px(length.to_px(*layout_node) / denominator);
|
||||
},
|
||||
[&](Time const& time) {
|
||||
m_value = Time::make_seconds(time.to_seconds() / denominator);
|
||||
},
|
||||
[&](Percentage const& percentage) {
|
||||
m_value = Percentage { percentage.value() / denominator };
|
||||
});
|
||||
|
@ -630,6 +660,31 @@ Optional<Percentage> CalculatedStyleValue::resolve_percentage() const
|
|||
return {};
|
||||
}
|
||||
|
||||
Optional<Time> CalculatedStyleValue::resolve_time() const
|
||||
{
|
||||
auto result = m_expression->resolve(nullptr, {});
|
||||
|
||||
if (result.value().has<Time>())
|
||||
return result.value().get<Time>();
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<TimePercentage> CalculatedStyleValue::resolve_time_percentage(Time const& percentage_basis) const
|
||||
{
|
||||
auto result = m_expression->resolve(nullptr, percentage_basis);
|
||||
|
||||
return result.value().visit(
|
||||
[&](Time const& time) -> Optional<TimePercentage> {
|
||||
return time;
|
||||
},
|
||||
[&](Percentage const& percentage) -> Optional<TimePercentage> {
|
||||
return percentage;
|
||||
},
|
||||
[&](auto const&) -> Optional<TimePercentage> {
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
Optional<float> CalculatedStyleValue::resolve_number()
|
||||
{
|
||||
auto result = m_expression->resolve(nullptr, {});
|
||||
|
@ -809,6 +864,7 @@ Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcValue::re
|
|||
[](Frequency const&) -> Optional<CalculatedStyleValue::ResolvedType> { return { ResolvedType::Frequency }; },
|
||||
[](Length const&) -> Optional<CalculatedStyleValue::ResolvedType> { return { ResolvedType::Length }; },
|
||||
[](Percentage const&) -> Optional<CalculatedStyleValue::ResolvedType> { return { ResolvedType::Percentage }; },
|
||||
[](Time const&) -> Optional<CalculatedStyleValue::ResolvedType> { return { ResolvedType::Time }; },
|
||||
[](NonnullOwnPtr<CalcSum> const& sum) { return sum->resolved_type(); });
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <LibWeb/CSS/Percentage.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
#include <LibWeb/CSS/Resolution.h>
|
||||
#include <LibWeb/CSS/Time.h>
|
||||
#include <LibWeb/CSS/ValueID.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Loader/ImageResource.h>
|
||||
|
@ -314,6 +315,7 @@ public:
|
|||
Resolution,
|
||||
String,
|
||||
TextDecoration,
|
||||
Time,
|
||||
Transformation,
|
||||
Unresolved,
|
||||
Unset,
|
||||
|
@ -348,6 +350,7 @@ public:
|
|||
bool is_resolution() const { return type() == Type::Resolution; }
|
||||
bool is_string() const { return type() == Type::String; }
|
||||
bool is_text_decoration() const { return type() == Type::TextDecoration; }
|
||||
bool is_time() const { return type() == Type::Time; }
|
||||
bool is_transformation() const { return type() == Type::Transformation; }
|
||||
bool is_unresolved() const { return type() == Type::Unresolved; }
|
||||
bool is_unset() const { return type() == Type::Unset; }
|
||||
|
@ -381,6 +384,7 @@ public:
|
|||
ResolutionStyleValue const& as_resolution() const;
|
||||
StringStyleValue const& as_string() const;
|
||||
TextDecorationStyleValue const& as_text_decoration() const;
|
||||
TimeStyleValue const& as_time() const;
|
||||
TransformationStyleValue const& as_transformation() const;
|
||||
UnresolvedStyleValue const& as_unresolved() const;
|
||||
UnsetStyleValue const& as_unset() const;
|
||||
|
@ -412,6 +416,7 @@ public:
|
|||
ResolutionStyleValue& as_resolution() { return const_cast<ResolutionStyleValue&>(const_cast<StyleValue const&>(*this).as_resolution()); }
|
||||
StringStyleValue& as_string() { return const_cast<StringStyleValue&>(const_cast<StyleValue const&>(*this).as_string()); }
|
||||
TextDecorationStyleValue& as_text_decoration() { return const_cast<TextDecorationStyleValue&>(const_cast<StyleValue const&>(*this).as_text_decoration()); }
|
||||
TimeStyleValue& as_time() { return const_cast<TimeStyleValue&>(const_cast<StyleValue const&>(*this).as_time()); }
|
||||
TransformationStyleValue& as_transformation() { return const_cast<TransformationStyleValue&>(const_cast<StyleValue const&>(*this).as_transformation()); }
|
||||
UnresolvedStyleValue& as_unresolved() { return const_cast<UnresolvedStyleValue&>(const_cast<StyleValue const&>(*this).as_unresolved()); }
|
||||
UnsetStyleValue& as_unset() { return const_cast<UnsetStyleValue&>(const_cast<StyleValue const&>(*this).as_unset()); }
|
||||
|
@ -740,11 +745,12 @@ public:
|
|||
float value;
|
||||
};
|
||||
|
||||
using PercentageBasis = Variant<Empty, Angle, Frequency, Length>;
|
||||
using PercentageBasis = Variant<Empty, Angle, Frequency, Length, Time>;
|
||||
|
||||
class CalculationResult {
|
||||
public:
|
||||
CalculationResult(Variant<Number, Angle, Frequency, Length, Percentage> value)
|
||||
using Value = Variant<Number, Angle, Frequency, Length, Percentage, Time>;
|
||||
CalculationResult(Value value)
|
||||
: m_value(move(value))
|
||||
{
|
||||
}
|
||||
|
@ -753,11 +759,11 @@ public:
|
|||
void multiply_by(CalculationResult const& other, Layout::Node const*);
|
||||
void divide_by(CalculationResult const& other, Layout::Node const*);
|
||||
|
||||
Variant<Number, Angle, Frequency, Length, Percentage> const& value() const { return m_value; }
|
||||
Value const& value() const { return m_value; }
|
||||
|
||||
private:
|
||||
void add_or_subtract_internal(SumOperation op, CalculationResult const& other, Layout::Node const*, PercentageBasis const& percentage_basis);
|
||||
Variant<Number, Angle, Frequency, Length, Percentage> m_value;
|
||||
Value m_value;
|
||||
};
|
||||
|
||||
struct CalcSum;
|
||||
|
@ -777,7 +783,7 @@ public:
|
|||
};
|
||||
|
||||
struct CalcValue {
|
||||
Variant<Number, Angle, Frequency, Length, Percentage, NonnullOwnPtr<CalcSum>> value;
|
||||
Variant<Number, Angle, Frequency, Length, Percentage, Time, NonnullOwnPtr<CalcSum>> value;
|
||||
String to_string() const;
|
||||
Optional<ResolvedType> resolved_type() const;
|
||||
CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const;
|
||||
|
@ -888,6 +894,8 @@ public:
|
|||
Optional<Length> resolve_length(Layout::Node const& layout_node) const;
|
||||
Optional<LengthPercentage> resolve_length_percentage(Layout::Node const&, Length const& percentage_basis) const;
|
||||
Optional<Percentage> resolve_percentage() const;
|
||||
Optional<Time> resolve_time() const;
|
||||
Optional<TimePercentage> resolve_time_percentage(Time const& percentage_basis) const;
|
||||
Optional<float> resolve_number();
|
||||
Optional<i64> resolve_integer();
|
||||
|
||||
|
@ -1455,6 +1463,35 @@ private:
|
|||
NonnullRefPtr<StyleValue> m_color;
|
||||
};
|
||||
|
||||
class TimeStyleValue : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<TimeStyleValue> create(Time time)
|
||||
{
|
||||
return adopt_ref(*new TimeStyleValue(move(time)));
|
||||
}
|
||||
virtual ~TimeStyleValue() override { }
|
||||
|
||||
Time const& time() const { return m_time; }
|
||||
|
||||
virtual String to_string() const override { return m_time.to_string(); }
|
||||
|
||||
virtual bool equals(StyleValue const& other) const override
|
||||
{
|
||||
if (type() != other.type())
|
||||
return false;
|
||||
return m_time == static_cast<TimeStyleValue const&>(other).m_time;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit TimeStyleValue(Time time)
|
||||
: StyleValue(Type::Time)
|
||||
, m_time(move(time))
|
||||
{
|
||||
}
|
||||
|
||||
Time m_time;
|
||||
};
|
||||
|
||||
class TransformationStyleValue final : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<TransformationStyleValue> create(CSS::TransformFunction transform_function, NonnullRefPtrVector<StyleValue>&& values)
|
||||
|
|
86
Userland/Libraries/LibWeb/CSS/Time.cpp
Normal file
86
Userland/Libraries/LibWeb/CSS/Time.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "Time.h"
|
||||
#include <LibWeb/CSS/StyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
Time::Time(int value, Type type)
|
||||
: m_type(type)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
Time::Time(float value, Type type)
|
||||
: m_type(type)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
Time Time::make_calculated(NonnullRefPtr<CalculatedStyleValue> calculated_style_value)
|
||||
{
|
||||
Time frequency { 0, Type::Calculated };
|
||||
frequency.m_calculated_style = move(calculated_style_value);
|
||||
return frequency;
|
||||
}
|
||||
|
||||
Time Time::make_seconds(float value)
|
||||
{
|
||||
return { value, Type::S };
|
||||
}
|
||||
|
||||
Time Time::percentage_of(Percentage const& percentage) const
|
||||
{
|
||||
VERIFY(!is_calculated());
|
||||
|
||||
return Time { percentage.as_fraction() * m_value, m_type };
|
||||
}
|
||||
|
||||
String Time::to_string() const
|
||||
{
|
||||
if (is_calculated())
|
||||
return m_calculated_style->to_string();
|
||||
return String::formatted("{}{}", m_value, unit_name());
|
||||
}
|
||||
|
||||
float Time::to_seconds() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::Calculated:
|
||||
return m_calculated_style->resolve_time()->to_seconds();
|
||||
case Type::S:
|
||||
return m_value;
|
||||
case Type::Ms:
|
||||
return m_value / 1000.0f;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
StringView Time::unit_name() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::Calculated:
|
||||
return "calculated"sv;
|
||||
case Type::S:
|
||||
return "s"sv;
|
||||
case Type::Ms:
|
||||
return "ms"sv;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
Optional<Time::Type> Time::unit_from_name(StringView name)
|
||||
{
|
||||
if (name.equals_ignoring_case("s"sv)) {
|
||||
return Type::S;
|
||||
} else if (name.equals_ignoring_case("ms"sv)) {
|
||||
return Type::Ms;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
55
Userland/Libraries/LibWeb/CSS/Time.h
Normal file
55
Userland/Libraries/LibWeb/CSS/Time.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/RefPtr.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class Time {
|
||||
public:
|
||||
enum class Type {
|
||||
Calculated,
|
||||
S,
|
||||
Ms,
|
||||
};
|
||||
|
||||
static Optional<Type> unit_from_name(StringView);
|
||||
|
||||
Time(int value, Type type);
|
||||
Time(float value, Type type);
|
||||
static Time make_calculated(NonnullRefPtr<CalculatedStyleValue>);
|
||||
static Time make_seconds(float);
|
||||
Time percentage_of(Percentage const&) const;
|
||||
|
||||
bool is_calculated() const { return m_type == Type::Calculated; }
|
||||
|
||||
String to_string() const;
|
||||
float to_seconds() const;
|
||||
|
||||
bool operator==(Time const& other) const
|
||||
{
|
||||
if (is_calculated())
|
||||
return m_calculated_style == other.m_calculated_style;
|
||||
return m_type == other.m_type && m_value == other.m_value;
|
||||
}
|
||||
|
||||
bool operator!=(Time const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
StringView unit_name() const;
|
||||
|
||||
Type m_type;
|
||||
float m_value { 0 };
|
||||
RefPtr<CalculatedStyleValue> m_calculated_style;
|
||||
};
|
||||
|
||||
}
|
|
@ -76,6 +76,9 @@ class StyleValue;
|
|||
class StyleValueList;
|
||||
class Supports;
|
||||
class TextDecorationStyleValue;
|
||||
class Time;
|
||||
class TimePercentage;
|
||||
class TimeStyleValue;
|
||||
class TransformationStyleValue;
|
||||
class UnresolvedStyleValue;
|
||||
class UnsetStyleValue;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue