LibWeb/CSS: Use generated FooUnit types instead of Foo::Type

I've also renamed the `m_type` and `type()` members to be `m_unit` and
`unit()` instead, to match what they actually are.
This commit is contained in:
Sam Atkins 2025-09-02 13:48:49 +01:00
commit b3e32445d3
Notes: github-actions[bot] 2025-09-11 16:08:15 +00:00
29 changed files with 232 additions and 669 deletions

View file

@ -12,20 +12,20 @@
namespace Web::CSS {
Angle::Angle(double value, Type type)
: m_type(type)
Angle::Angle(double value, AngleUnit unit)
: m_unit(unit)
, m_value(value)
{
}
Angle Angle::make_degrees(double value)
{
return { value, Type::Deg };
return { value, AngleUnit::Deg };
}
Angle Angle::percentage_of(Percentage const& percentage) const
{
return Angle { percentage.as_fraction() * m_value, m_type };
return Angle { percentage.as_fraction() * m_value, m_unit };
}
String Angle::to_string(SerializationMode serialization_mode) const
@ -48,14 +48,14 @@ String Angle::to_string(SerializationMode serialization_mode) const
double Angle::to_degrees() const
{
switch (m_type) {
case Type::Deg:
switch (m_unit) {
case AngleUnit::Deg:
return m_value;
case Type::Grad:
case AngleUnit::Grad:
return m_value * (360.0 / 400.0);
case Type::Rad:
case AngleUnit::Rad:
return AK::to_degrees(m_value);
case Type::Turn:
case AngleUnit::Turn:
return m_value * 360.0;
}
VERIFY_NOT_REACHED();
@ -66,38 +66,6 @@ double Angle::to_radians() const
return AK::to_radians(to_degrees());
}
StringView Angle::unit_name() const
{
switch (m_type) {
case Type::Deg:
return "deg"sv;
case Type::Grad:
return "grad"sv;
case Type::Rad:
return "rad"sv;
case Type::Turn:
return "turn"sv;
}
VERIFY_NOT_REACHED();
}
Optional<Angle::Type> Angle::unit_from_name(StringView name)
{
if (name.equals_ignoring_ascii_case("deg"sv)) {
return Type::Deg;
}
if (name.equals_ignoring_ascii_case("grad"sv)) {
return Type::Grad;
}
if (name.equals_ignoring_ascii_case("rad"sv)) {
return Type::Rad;
}
if (name.equals_ignoring_ascii_case("turn"sv)) {
return Type::Turn;
}
return {};
}
Angle Angle::resolve_calculated(NonnullRefPtr<CalculatedStyleValue const> const& calculated, Layout::Node const& layout_node, Angle const& reference_value)
{
CalculationResolutionContext context {

View file

@ -15,16 +15,7 @@ namespace Web::CSS {
class Angle {
public:
enum class Type : u8 {
Deg,
Grad,
Rad,
Turn,
};
static Optional<Type> unit_from_name(StringView);
Angle(double value, Type type);
Angle(double value, AngleUnit unit);
static Angle make_degrees(double);
Angle percentage_of(Percentage const&) const;
@ -33,13 +24,13 @@ public:
double to_degrees() const;
double to_radians() const;
Type type() const { return m_type; }
double raw_value() const { return m_value; }
StringView unit_name() const;
AngleUnit unit() const { return m_unit; }
StringView unit_name() const { return CSS::to_string(m_unit); }
bool operator==(Angle const& other) const
{
return m_type == other.m_type && m_value == other.m_value;
return m_unit == other.m_unit && m_value == other.m_value;
}
int operator<=>(Angle const& other) const
@ -57,7 +48,7 @@ public:
static Angle resolve_calculated(NonnullRefPtr<CalculatedStyleValue const> const&, Layout::Node const&, Angle const& reference_value);
private:
Type m_type;
AngleUnit m_unit;
double m_value { 0 };
};

View file

@ -378,17 +378,17 @@ CSSPixels ComputedProperties::compute_line_height(CSSPixelRect const& viewport_r
return line_height.as_length().length().to_px(viewport_rect, font_metrics, root_font_metrics);
if (line_height.is_number())
return Length(line_height.as_number().number(), Length::Type::Em).to_px(viewport_rect, font_metrics, root_font_metrics);
return Length(line_height.as_number().number(), LengthUnit::Em).to_px(viewport_rect, font_metrics, root_font_metrics);
if (line_height.is_percentage()) {
// Percentages are relative to 1em. https://www.w3.org/TR/css-inline-3/#valdef-line-height-percentage
auto const& percentage = line_height.as_percentage().percentage();
return Length(percentage.as_fraction(), Length::Type::Em).to_px(viewport_rect, font_metrics, root_font_metrics);
return Length(percentage.as_fraction(), LengthUnit::Em).to_px(viewport_rect, font_metrics, root_font_metrics);
}
if (line_height.is_calculated()) {
CalculationResolutionContext context {
.percentage_basis = Length(1, Length::Type::Em),
.percentage_basis = Length(1, LengthUnit::Em),
.length_resolution_context = Length::ResolutionContext { viewport_rect, font_metrics, root_font_metrics },
};
if (line_height.as_calculated().resolves_to_number()) {
@ -397,7 +397,7 @@ CSSPixels ComputedProperties::compute_line_height(CSSPixelRect const& viewport_r
dbgln("FIXME: Failed to resolve calc() line-height (number): {}", line_height.as_calculated().to_string(SerializationMode::Normal));
return CSSPixels::nearest_value_for(m_font_list->first().pixel_metrics().line_spacing());
}
return Length(resolved.value(), Length::Type::Em).to_px(viewport_rect, font_metrics, root_font_metrics);
return Length(resolved.value(), LengthUnit::Em).to_px(viewport_rect, font_metrics, root_font_metrics);
}
auto resolved = line_height.as_calculated().resolve_length_deprecated(context);
@ -565,7 +565,7 @@ Length ComputedProperties::border_spacing_horizontal(Layout::Node const& layout_
if (style_value.is_length())
return style_value.as_length().length();
if (style_value.is_calculated())
return style_value.as_calculated().resolve_length_deprecated({ .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }).value_or(Length(0, Length::Type::Px));
return style_value.as_calculated().resolve_length_deprecated({ .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }).value_or(Length::make_px(0));
return {};
};
@ -587,7 +587,7 @@ Length ComputedProperties::border_spacing_vertical(Layout::Node const& layout_no
if (style_value.is_length())
return style_value.as_length().length();
if (style_value.is_calculated())
return style_value.as_calculated().resolve_length_deprecated({ .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }).value_or(Length(0, Length::Type::Px));
return style_value.as_calculated().resolve_length_deprecated({ .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }).value_or(Length::make_px(0));
return {};
};

View file

@ -10,20 +10,20 @@
namespace Web::CSS {
Flex::Flex(double value, Type type)
: m_type(type)
Flex::Flex(double value, FlexUnit unit)
: m_unit(unit)
, m_value(value)
{
}
Flex Flex::make_fr(double value)
{
return { value, Type::Fr };
return { value, FlexUnit::Fr };
}
Flex Flex::percentage_of(Percentage const& percentage) const
{
return Flex { percentage.as_fraction() * m_value, m_type };
return Flex { percentage.as_fraction() * m_value, m_unit };
}
String Flex::to_string(SerializationMode serialization_mode) const
@ -44,28 +44,11 @@ String Flex::to_string(SerializationMode serialization_mode) const
double Flex::to_fr() const
{
switch (m_type) {
case Type::Fr:
switch (m_unit) {
case FlexUnit::Fr:
return m_value;
}
VERIFY_NOT_REACHED();
}
StringView Flex::unit_name() const
{
switch (m_type) {
case Type::Fr:
return "fr"sv;
}
VERIFY_NOT_REACHED();
}
Optional<Flex::Type> Flex::unit_from_name(StringView name)
{
if (name.equals_ignoring_ascii_case("fr"sv))
return Type::Fr;
return {};
}
}

View file

@ -6,9 +6,9 @@
#pragma once
#include <AK/Optional.h>
#include <AK/String.h>
#include <LibWeb/CSS/SerializationMode.h>
#include <LibWeb/CSS/Units.h>
#include <LibWeb/Forward.h>
namespace Web::CSS {
@ -16,26 +16,20 @@ namespace Web::CSS {
// https://drafts.csswg.org/css-grid-2/#typedef-flex
class Flex {
public:
enum class Type : u8 {
Fr,
};
static Optional<Type> unit_from_name(StringView);
Flex(double value, Type type);
Flex(double value, FlexUnit unit);
static Flex make_fr(double);
Flex percentage_of(Percentage const&) const;
String to_string(SerializationMode = SerializationMode::Normal) const;
double to_fr() const;
Type type() const { return m_type; }
double raw_value() const { return m_value; }
StringView unit_name() const;
FlexUnit unit() const { return m_unit; }
StringView unit_name() const { return CSS::to_string(m_unit); }
bool operator==(Flex const& other) const
{
return m_type == other.m_type && m_value == other.m_value;
return m_unit == other.m_unit && m_value == other.m_value;
}
int operator<=>(Flex const& other) const
@ -51,7 +45,7 @@ public:
}
private:
Type m_type;
FlexUnit m_unit;
double m_value { 0 };
};

View file

@ -11,20 +11,20 @@
namespace Web::CSS {
Frequency::Frequency(double value, Type type)
: m_type(type)
Frequency::Frequency(double value, FrequencyUnit unit)
: m_unit(unit)
, m_value(value)
{
}
Frequency Frequency::make_hertz(double value)
{
return { value, Type::Hz };
return { value, FrequencyUnit::Hz };
}
Frequency Frequency::percentage_of(Percentage const& percentage) const
{
return Frequency { percentage.as_fraction() * m_value, m_type };
return Frequency { percentage.as_fraction() * m_value, m_unit };
}
String Frequency::to_string(SerializationMode serialization_mode) const
@ -47,36 +47,15 @@ String Frequency::to_string(SerializationMode serialization_mode) const
double Frequency::to_hertz() const
{
switch (m_type) {
case Type::Hz:
switch (m_unit) {
case FrequencyUnit::Hz:
return m_value;
case Type::kHz:
case FrequencyUnit::KHz:
return m_value * 1000;
}
VERIFY_NOT_REACHED();
}
StringView Frequency::unit_name() const
{
switch (m_type) {
case Type::Hz:
return "hz"sv;
case Type::kHz:
return "khz"sv;
}
VERIFY_NOT_REACHED();
}
Optional<Frequency::Type> Frequency::unit_from_name(StringView name)
{
if (name.equals_ignoring_ascii_case("hz"sv)) {
return Type::Hz;
} else if (name.equals_ignoring_ascii_case("khz"sv)) {
return Type::kHz;
}
return {};
}
Frequency Frequency::resolve_calculated(NonnullRefPtr<CalculatedStyleValue const> const& calculated, Layout::Node const& layout_node, Frequency const& reference_value)
{
CalculationResolutionContext context {

View file

@ -8,33 +8,27 @@
#include <AK/String.h>
#include <LibWeb/CSS/SerializationMode.h>
#include <LibWeb/CSS/Units.h>
#include <LibWeb/Forward.h>
namespace Web::CSS {
class Frequency {
public:
enum class Type : u8 {
Hz,
kHz
};
static Optional<Type> unit_from_name(StringView);
Frequency(double value, Type type);
Frequency(double value, FrequencyUnit unit);
static Frequency make_hertz(double);
Frequency percentage_of(Percentage const&) const;
String to_string(SerializationMode = SerializationMode::Normal) const;
double to_hertz() const;
Type type() const { return m_type; }
double raw_value() const { return m_value; }
StringView unit_name() const;
FrequencyUnit unit() const { return m_unit; }
StringView unit_name() const { return CSS::to_string(m_unit); }
bool operator==(Frequency const& other) const
{
return m_type == other.m_type && m_value == other.m_value;
return m_unit == other.m_unit && m_value == other.m_value;
}
int operator<=>(Frequency const& other) const
@ -52,7 +46,7 @@ public:
static Frequency resolve_calculated(NonnullRefPtr<CalculatedStyleValue const> const&, Layout::Node const&, Frequency const& reference_value);
private:
Type m_type;
FrequencyUnit m_unit;
double m_value { 0 };
};

View file

@ -1235,7 +1235,7 @@ static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, Ca
auto const& from_length = from.as_length().length();
auto const& to_length = to.as_length().length();
auto interpolated_value = interpolate_raw(from_length.raw_value(), to_length.raw_value(), delta, calculation_context.accepted_type_ranges.get(ValueType::Length));
return LengthStyleValue::create(Length(interpolated_value, from_length.type()));
return LengthStyleValue::create(Length(interpolated_value, from_length.unit()));
}
case StyleValue::Type::Number: {
auto interpolated_value = interpolate_raw(from.as_number().number(), to.as_number().number(), delta, calculation_context.accepted_type_ranges.get(ValueType::Number));
@ -1287,7 +1287,7 @@ static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, Ca
return LengthOrAuto::make_auto();
// FIXME: Actually handle the units not matching.
auto interpolated_value = interpolate_raw(from.length().raw_value(), to.length().raw_value(), delta, calculation_context.accepted_type_ranges.get(ValueType::Rect));
return LengthOrAuto { Length { interpolated_value, from.length().type() } };
return LengthOrAuto { Length { interpolated_value, from.length().unit() } };
};
return RectStyleValue::create({

View file

@ -31,8 +31,8 @@ Length::FontMetrics::FontMetrics(CSSPixels font_size, Gfx::FontPixelMetrics cons
{
}
Length::Length(double value, Type type)
: m_type(type)
Length::Length(double value, LengthUnit unit)
: m_unit(unit)
, m_value(value)
{
}
@ -40,7 +40,7 @@ Length::~Length() = default;
Length Length::make_px(double value)
{
return Length(value, Type::Px);
return Length(value, LengthUnit::Px);
}
Length Length::make_px(CSSPixels value)
@ -50,37 +50,37 @@ Length Length::make_px(CSSPixels value)
Length Length::percentage_of(Percentage const& percentage) const
{
return Length { percentage.as_fraction() * raw_value(), m_type };
return Length { percentage.as_fraction() * raw_value(), m_unit };
}
CSSPixels Length::font_relative_length_to_px(Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const
{
switch (m_type) {
case Type::Em:
switch (m_unit) {
case LengthUnit::Em:
return CSSPixels::nearest_value_for(m_value * font_metrics.font_size.to_double());
case Type::Rem:
case LengthUnit::Rem:
return CSSPixels::nearest_value_for(m_value * root_font_metrics.font_size.to_double());
case Type::Ex:
case LengthUnit::Ex:
return CSSPixels::nearest_value_for(m_value * font_metrics.x_height.to_double());
case Type::Rex:
case LengthUnit::Rex:
return CSSPixels::nearest_value_for(m_value * root_font_metrics.x_height.to_double());
case Type::Cap:
case LengthUnit::Cap:
return CSSPixels::nearest_value_for(m_value * font_metrics.cap_height.to_double());
case Type::Rcap:
case LengthUnit::Rcap:
return CSSPixels::nearest_value_for(m_value * root_font_metrics.cap_height.to_double());
case Type::Ch:
case LengthUnit::Ch:
return CSSPixels::nearest_value_for(m_value * font_metrics.zero_advance.to_double());
case Type::Rch:
case LengthUnit::Rch:
return CSSPixels::nearest_value_for(m_value * root_font_metrics.zero_advance.to_double());
case Type::Ic:
case LengthUnit::Ic:
// FIXME: Use the "advance measure of the “水” (CJK water ideograph, U+6C34) glyph"
return CSSPixels::nearest_value_for(m_value * font_metrics.font_size.to_double());
case Type::Ric:
case LengthUnit::Ric:
// FIXME: Use the "advance measure of the “水” (CJK water ideograph, U+6C34) glyph"
return CSSPixels::nearest_value_for(m_value * root_font_metrics.font_size.to_double());
case Type::Lh:
case LengthUnit::Lh:
return CSSPixels::nearest_value_for(m_value * font_metrics.line_height.to_double());
case Type::Rlh:
case LengthUnit::Rlh:
return CSSPixels::nearest_value_for(m_value * root_font_metrics.line_height.to_double());
default:
VERIFY_NOT_REACHED();
@ -89,38 +89,38 @@ CSSPixels Length::font_relative_length_to_px(Length::FontMetrics const& font_met
CSSPixels Length::viewport_relative_length_to_px(CSSPixelRect const& viewport_rect) const
{
switch (m_type) {
case Type::Vw:
case Type::Svw:
case Type::Lvw:
case Type::Dvw:
switch (m_unit) {
case LengthUnit::Vw:
case LengthUnit::Svw:
case LengthUnit::Lvw:
case LengthUnit::Dvw:
return viewport_rect.width() * (CSSPixels::nearest_value_for(m_value) / 100);
case Type::Vh:
case Type::Svh:
case Type::Lvh:
case Type::Dvh:
case LengthUnit::Vh:
case LengthUnit::Svh:
case LengthUnit::Lvh:
case LengthUnit::Dvh:
return viewport_rect.height() * (CSSPixels::nearest_value_for(m_value) / 100);
case Type::Vi:
case Type::Svi:
case Type::Lvi:
case Type::Dvi:
case LengthUnit::Vi:
case LengthUnit::Svi:
case LengthUnit::Lvi:
case LengthUnit::Dvi:
// FIXME: Select the width or height based on which is the inline axis.
return viewport_rect.width() * (CSSPixels::nearest_value_for(m_value) / 100);
case Type::Vb:
case Type::Svb:
case Type::Lvb:
case Type::Dvb:
case LengthUnit::Vb:
case LengthUnit::Svb:
case LengthUnit::Lvb:
case LengthUnit::Dvb:
// FIXME: Select the width or height based on which is the block axis.
return viewport_rect.height() * (CSSPixels::nearest_value_for(m_value) / 100);
case Type::Vmin:
case Type::Svmin:
case Type::Lvmin:
case Type::Dvmin:
case LengthUnit::Vmin:
case LengthUnit::Svmin:
case LengthUnit::Lvmin:
case LengthUnit::Dvmin:
return min(viewport_rect.width(), viewport_rect.height()) * (CSSPixels::nearest_value_for(m_value) / 100);
case Type::Vmax:
case Type::Svmax:
case Type::Lvmax:
case Type::Dvmax:
case LengthUnit::Vmax:
case LengthUnit::Svmax:
case LengthUnit::Lvmax:
case LengthUnit::Dvmax:
return max(viewport_rect.width(), viewport_rect.height()) * (CSSPixels::nearest_value_for(m_value) / 100);
default:
VERIFY_NOT_REACHED();
@ -215,7 +215,7 @@ String Length::to_string(SerializationMode serialization_mode) const
// FIXME: Manually skip this for px so we avoid rounding errors in absolute_length_to_px.
// Maybe provide alternative functions that don't produce CSSPixels?
if (serialization_mode == SerializationMode::ResolvedValue && is_absolute() && m_type != Type::Px) {
if (serialization_mode == SerializationMode::ResolvedValue && is_absolute() && m_unit != LengthUnit::Px) {
StringBuilder builder;
serialize_a_number(builder, absolute_length_to_px().to_double());
builder.append("px"sv);
@ -227,192 +227,6 @@ String Length::to_string(SerializationMode serialization_mode) const
return builder.to_string_without_validation();
}
StringView Length::unit_name() const
{
switch (m_type) {
case Type::Em:
return "em"sv;
case Type::Rem:
return "rem"sv;
case Type::Ex:
return "ex"sv;
case Type::Rex:
return "rex"sv;
case Type::Cap:
return "cap"sv;
case Type::Rcap:
return "rcap"sv;
case Type::Ch:
return "ch"sv;
case Type::Rch:
return "rch"sv;
case Type::Ic:
return "ic"sv;
case Type::Ric:
return "ric"sv;
case Type::Lh:
return "lh"sv;
case Type::Rlh:
return "rlh"sv;
case Type::Vw:
return "vw"sv;
case Type::Svw:
return "svw"sv;
case Type::Lvw:
return "lvw"sv;
case Type::Dvw:
return "dvw"sv;
case Type::Vh:
return "vh"sv;
case Type::Svh:
return "svh"sv;
case Type::Lvh:
return "lvh"sv;
case Type::Dvh:
return "dvh"sv;
case Type::Vi:
return "vi"sv;
case Type::Svi:
return "svi"sv;
case Type::Lvi:
return "lvi"sv;
case Type::Dvi:
return "dvi"sv;
case Type::Vb:
return "vb"sv;
case Type::Svb:
return "svb"sv;
case Type::Lvb:
return "lvb"sv;
case Type::Dvb:
return "dvb"sv;
case Type::Vmin:
return "vmin"sv;
case Type::Svmin:
return "svmin"sv;
case Type::Lvmin:
return "lvmin"sv;
case Type::Dvmin:
return "dvmin"sv;
case Type::Vmax:
return "vmax"sv;
case Type::Svmax:
return "svmax"sv;
case Type::Lvmax:
return "lvmax"sv;
case Type::Dvmax:
return "dvmax"sv;
case Type::Cm:
return "cm"sv;
case Type::Mm:
return "mm"sv;
case Type::Q:
return "Q"sv;
case Type::In:
return "in"sv;
case Type::Pt:
return "pt"sv;
case Type::Pc:
return "pc"sv;
case Type::Px:
return "px"sv;
}
VERIFY_NOT_REACHED();
}
Optional<Length::Type> Length::unit_from_name(StringView name)
{
if (name.equals_ignoring_ascii_case("em"sv)) {
return Length::Type::Em;
} else if (name.equals_ignoring_ascii_case("rem"sv)) {
return Length::Type::Rem;
} else if (name.equals_ignoring_ascii_case("ex"sv)) {
return Length::Type::Ex;
} else if (name.equals_ignoring_ascii_case("rex"sv)) {
return Length::Type::Rex;
} else if (name.equals_ignoring_ascii_case("cap"sv)) {
return Length::Type::Cap;
} else if (name.equals_ignoring_ascii_case("rcap"sv)) {
return Length::Type::Rcap;
} else if (name.equals_ignoring_ascii_case("ch"sv)) {
return Length::Type::Ch;
} else if (name.equals_ignoring_ascii_case("rch"sv)) {
return Length::Type::Rch;
} else if (name.equals_ignoring_ascii_case("ic"sv)) {
return Length::Type::Ic;
} else if (name.equals_ignoring_ascii_case("ric"sv)) {
return Length::Type::Ric;
} else if (name.equals_ignoring_ascii_case("lh"sv)) {
return Length::Type::Lh;
} else if (name.equals_ignoring_ascii_case("rlh"sv)) {
return Length::Type::Rlh;
} else if (name.equals_ignoring_ascii_case("vw"sv)) {
return Length::Type::Vw;
} else if (name.equals_ignoring_ascii_case("svw"sv)) {
return Length::Type::Svw;
} else if (name.equals_ignoring_ascii_case("lvw"sv)) {
return Length::Type::Lvw;
} else if (name.equals_ignoring_ascii_case("dvw"sv)) {
return Length::Type::Dvw;
} else if (name.equals_ignoring_ascii_case("vh"sv)) {
return Length::Type::Vh;
} else if (name.equals_ignoring_ascii_case("svh"sv)) {
return Length::Type::Svh;
} else if (name.equals_ignoring_ascii_case("lvh"sv)) {
return Length::Type::Lvh;
} else if (name.equals_ignoring_ascii_case("dvh"sv)) {
return Length::Type::Dvh;
} else if (name.equals_ignoring_ascii_case("vi"sv)) {
return Length::Type::Vi;
} else if (name.equals_ignoring_ascii_case("svi"sv)) {
return Length::Type::Svi;
} else if (name.equals_ignoring_ascii_case("lvi"sv)) {
return Length::Type::Lvi;
} else if (name.equals_ignoring_ascii_case("dvi"sv)) {
return Length::Type::Dvi;
} else if (name.equals_ignoring_ascii_case("vb"sv)) {
return Length::Type::Vb;
} else if (name.equals_ignoring_ascii_case("svb"sv)) {
return Length::Type::Svb;
} else if (name.equals_ignoring_ascii_case("lvb"sv)) {
return Length::Type::Lvb;
} else if (name.equals_ignoring_ascii_case("dvb"sv)) {
return Length::Type::Dvb;
} else if (name.equals_ignoring_ascii_case("vmin"sv)) {
return Length::Type::Vmin;
} else if (name.equals_ignoring_ascii_case("svmin"sv)) {
return Length::Type::Svmin;
} else if (name.equals_ignoring_ascii_case("lvmin"sv)) {
return Length::Type::Lvmin;
} else if (name.equals_ignoring_ascii_case("dvmin"sv)) {
return Length::Type::Dvmin;
} else if (name.equals_ignoring_ascii_case("vmax"sv)) {
return Length::Type::Vmax;
} else if (name.equals_ignoring_ascii_case("svmax"sv)) {
return Length::Type::Svmax;
} else if (name.equals_ignoring_ascii_case("lvmax"sv)) {
return Length::Type::Lvmax;
} else if (name.equals_ignoring_ascii_case("dvmax"sv)) {
return Length::Type::Dvmax;
} else if (name.equals_ignoring_ascii_case("cm"sv)) {
return Length::Type::Cm;
} else if (name.equals_ignoring_ascii_case("mm"sv)) {
return Length::Type::Mm;
} else if (name.equals_ignoring_ascii_case("Q"sv)) {
return Length::Type::Q;
} else if (name.equals_ignoring_ascii_case("in"sv)) {
return Length::Type::In;
} else if (name.equals_ignoring_ascii_case("pt"sv)) {
return Length::Type::Pt;
} else if (name.equals_ignoring_ascii_case("pc"sv)) {
return Length::Type::Pc;
} else if (name.equals_ignoring_ascii_case("px"sv)) {
return Length::Type::Px;
}
return {};
}
Optional<Length> Length::absolutize(CSSPixelRect const& viewport_rect, FontMetrics const& font_metrics, FontMetrics const& root_font_metrics) const
{
if (is_px())

View file

@ -11,6 +11,7 @@
#include <LibGfx/Forward.h>
#include <LibGfx/Rect.h>
#include <LibWeb/CSS/SerializationMode.h>
#include <LibWeb/CSS/Units.h>
#include <LibWeb/Export.h>
#include <LibWeb/Forward.h>
#include <LibWeb/PixelUnits.h>
@ -19,57 +20,6 @@ namespace Web::CSS {
class WEB_API Length {
public:
enum class Type : u8 {
// Font-relative
Em,
Rem,
Ex,
Rex,
Cap,
Rcap,
Ch,
Rch,
Ic,
Ric,
Lh,
Rlh,
// Viewport-relative
Vw,
Svw,
Lvw,
Dvw,
Vh,
Svh,
Lvh,
Dvh,
Vi,
Svi,
Lvi,
Dvi,
Vb,
Svb,
Lvb,
Dvb,
Vmin,
Svmin,
Lvmin,
Dvmin,
Vmax,
Svmax,
Lvmax,
Dvmax,
// Absolute
Cm,
Mm,
Q,
In,
Pt,
Pc,
Px,
};
struct FontMetrics {
FontMetrics(CSSPixels font_size, Gfx::FontPixelMetrics const&);
@ -82,80 +32,23 @@ public:
bool operator==(FontMetrics const&) const = default;
};
static Optional<Type> unit_from_name(StringView);
Length(double value, Type type);
Length(double value, LengthUnit unit);
~Length();
static Length make_px(double value);
static Length make_px(CSSPixels value);
Length percentage_of(Percentage const&) const;
bool is_px() const { return m_type == Type::Px; }
bool is_px() const { return m_unit == LengthUnit::Px; }
bool is_absolute() const
{
return m_type == Type::Cm
|| m_type == Type::Mm
|| m_type == Type::Q
|| m_type == Type::In
|| m_type == Type::Pt
|| m_type == Type::Pc
|| m_type == Type::Px;
}
bool is_absolute() const { return CSS::is_absolute(m_unit); }
bool is_font_relative() const { return CSS::is_font_relative(m_unit); }
bool is_viewport_relative() const { return CSS::is_viewport_relative(m_unit); }
bool is_relative() const { return CSS::is_relative(m_unit); }
bool is_font_relative() const
{
return m_type == Type::Em
|| m_type == Type::Rem
|| m_type == Type::Ex
|| m_type == Type::Rex
|| m_type == Type::Cap
|| m_type == Type::Rcap
|| m_type == Type::Ch
|| m_type == Type::Rch
|| m_type == Type::Ic
|| m_type == Type::Ric
|| m_type == Type::Lh
|| m_type == Type::Rlh;
}
bool is_viewport_relative() const
{
return m_type == Type::Vw
|| m_type == Type::Svw
|| m_type == Type::Lvw
|| m_type == Type::Dvw
|| m_type == Type::Vh
|| m_type == Type::Svh
|| m_type == Type::Lvh
|| m_type == Type::Dvh
|| m_type == Type::Vi
|| m_type == Type::Svi
|| m_type == Type::Lvi
|| m_type == Type::Dvi
|| m_type == Type::Vb
|| m_type == Type::Svb
|| m_type == Type::Lvb
|| m_type == Type::Dvb
|| m_type == Type::Vmin
|| m_type == Type::Svmin
|| m_type == Type::Lvmin
|| m_type == Type::Dvmin
|| m_type == Type::Vmax
|| m_type == Type::Svmax
|| m_type == Type::Lvmax
|| m_type == Type::Dvmax;
}
bool is_relative() const
{
return is_font_relative() || is_viewport_relative();
}
Type type() const { return m_type; }
double raw_value() const { return m_value; }
StringView unit_name() const;
LengthUnit unit() const { return m_unit; }
StringView unit_name() const { return CSS::to_string(m_unit); }
struct ResolutionContext {
[[nodiscard]] static ResolutionContext for_element(DOM::AbstractElement const&);
@ -200,20 +93,20 @@ public:
constexpr double inch_pixels = 96.0;
constexpr double centimeter_pixels = (inch_pixels / 2.54);
switch (m_type) {
case Type::Cm:
switch (m_unit) {
case LengthUnit::Cm:
return m_value * centimeter_pixels; // 1cm = 96px/2.54
case Type::In:
case LengthUnit::In:
return m_value * inch_pixels; // 1in = 2.54 cm = 96px
case Type::Px:
case LengthUnit::Px:
return m_value; // 1px = 1/96th of 1in
case Type::Pt:
case LengthUnit::Pt:
return m_value * ((1.0 / 72.0) * inch_pixels); // 1pt = 1/72th of 1in
case Type::Pc:
case LengthUnit::Pc:
return m_value * ((1.0 / 6.0) * inch_pixels); // 1pc = 1/6th of 1in
case Type::Mm:
case LengthUnit::Mm:
return m_value * ((1.0 / 10.0) * centimeter_pixels); // 1mm = 1/10th of 1cm
case Type::Q:
case LengthUnit::Q:
return m_value * ((1.0 / 40.0) * centimeter_pixels); // 1Q = 1/40th of 1cm
default:
VERIFY_NOT_REACHED();
@ -224,7 +117,7 @@ public:
bool operator==(Length const& other) const
{
return m_type == other.m_type && m_value == other.m_value;
return m_unit == other.m_unit && m_value == other.m_value;
}
CSSPixels font_relative_length_to_px(FontMetrics const& font_metrics, FontMetrics const& root_font_metrics) const;
@ -240,7 +133,7 @@ public:
private:
[[nodiscard]] CSSPixels to_px_slow_case(Layout::Node const&) const;
Type m_type;
LengthUnit m_unit;
double m_value { 0 };
};

View file

@ -56,37 +56,37 @@ Optional<NumericType> NumericType::create_from_unit(StringView unit)
}
// unit is a <length> unit
if (Length::unit_from_name(unit).has_value()) {
if (string_to_length_unit(unit).has_value()) {
// Return «[ "length" → 1 ]»
return NumericType { BaseType::Length, 1 };
}
// unit is an <angle> unit
if (Angle::unit_from_name(unit).has_value()) {
if (string_to_angle_unit(unit).has_value()) {
// Return «[ "angle" → 1 ]»
return NumericType { BaseType::Angle, 1 };
}
// unit is a <time> unit
if (Time::unit_from_name(unit).has_value()) {
if (string_to_time_unit(unit).has_value()) {
// Return «[ "time" → 1 ]»
return NumericType { BaseType::Time, 1 };
}
// unit is a <frequency> unit
if (Frequency::unit_from_name(unit).has_value()) {
if (string_to_frequency_unit(unit).has_value()) {
// Return «[ "frequency" → 1 ]»
return NumericType { BaseType::Frequency, 1 };
}
// unit is a <resolution> unit
if (Resolution::unit_from_name(unit).has_value()) {
if (string_to_resolution_unit(unit).has_value()) {
// Return «[ "resolution" → 1 ]»
return NumericType { BaseType::Resolution, 1 };
}
// unit is a <flex> unit
if (Flex::unit_from_name(unit).has_value()) {
if (string_to_flex_unit(unit).has_value()) {
// Return «[ "flex" → 1 ]»
return NumericType { BaseType::Flex, 1 };
}

View file

@ -131,12 +131,12 @@ static Vector<ComponentValue> replace_an_attr_function(DOM::AbstractElement& ele
first_argument_tokens.discard_a_token(); // raw-string
syntax = RawString {};
} else if (syntax_ident == "%"sv
|| Angle::unit_from_name(syntax_ident).has_value()
|| Flex::unit_from_name(syntax_ident).has_value()
|| Frequency::unit_from_name(syntax_ident).has_value()
|| Length::unit_from_name(syntax_ident).has_value()
|| Resolution::unit_from_name(syntax_ident).has_value()
|| Time::unit_from_name(syntax_ident).has_value()) {
|| string_to_angle_unit(syntax_ident).has_value()
|| string_to_flex_unit(syntax_ident).has_value()
|| string_to_frequency_unit(syntax_ident).has_value()
|| string_to_length_unit(syntax_ident).has_value()
|| string_to_resolution_unit(syntax_ident).has_value()
|| string_to_time_unit(syntax_ident).has_value()) {
syntax = TypeSyntaxNode::create("number"_fly_string).release_nonnull<SyntaxNode>();
unit_name = first_argument_tokens.consume_a_token().token().ident();
} else {

View file

@ -292,7 +292,7 @@ RefPtr<LinearGradientStyleValue const> Parser::parse_linear_gradient_function(To
tokens.discard_a_token(); // <angle>
auto angle_value = first_param.token().dimension_value();
auto unit_string = first_param.token().dimension_unit();
auto angle_type = Angle::unit_from_name(unit_string);
auto angle_type = string_to_angle_unit(unit_string);
if (!angle_type.has_value())
return nullptr;
@ -395,7 +395,7 @@ RefPtr<ConicGradientStyleValue const> Parser::parse_conic_gradient_function(Toke
if (!tokens.has_next_token())
return nullptr;
Angle from_angle(0, Angle::Type::Deg);
auto from_angle = Angle::make_degrees(0);
RefPtr<PositionStyleValue const> at_position;
Optional<InterpolationMethod> maybe_interpolation_method;
@ -426,7 +426,7 @@ RefPtr<ConicGradientStyleValue const> Parser::parse_conic_gradient_function(Toke
if (angle_token.is(Token::Type::Dimension)) {
auto angle = angle_token.token().dimension_value();
auto angle_unit = angle_token.token().dimension_unit();
auto angle_type = Angle::unit_from_name(angle_unit);
auto angle_type = string_to_angle_unit(angle_unit);
if (!angle_type.has_value())
return nullptr;

View file

@ -1729,7 +1729,7 @@ LengthOrCalculated Parser::parse_as_sizes_attribute(DOM::Element const& element,
// AD-HOC: If element has no sizes attribute, this algorithm always logs a parse error and then returns 100vw.
// The attribute is optional, so avoid spamming the debug log with false positives by just returning early.
if (!element.has_attribute(HTML::AttributeNames::sizes))
return Length(100, Length::Type::Vw);
return Length(100, LengthUnit::Vw);
// 1. Let unparsed sizes list be the result of parsing a comma-separated list of component values
// from the value of element's sizes attribute (or the empty string, if the attribute is absent).
@ -1828,7 +1828,7 @@ LengthOrCalculated Parser::parse_as_sizes_attribute(DOM::Element const& element,
}
// 4. Return 100vw.
return Length(100, Length::Type::Vw);
return Length(100, LengthUnit::Vw);
}
bool Parser::has_ignored_vendor_prefix(StringView string)

View file

@ -158,22 +158,22 @@ Optional<Dimension> Parser::parse_dimension(ComponentValue const& component_valu
auto numeric_value = component_value.token().dimension_value();
auto unit_string = component_value.token().dimension_unit();
if (auto length_type = Length::unit_from_name(unit_string); length_type.has_value())
if (auto length_type = string_to_length_unit(unit_string); length_type.has_value())
return Length { numeric_value, length_type.release_value() };
if (auto angle_type = Angle::unit_from_name(unit_string); angle_type.has_value())
if (auto angle_type = string_to_angle_unit(unit_string); angle_type.has_value())
return Angle { numeric_value, angle_type.release_value() };
if (auto flex_type = Flex::unit_from_name(unit_string); flex_type.has_value())
if (auto flex_type = string_to_flex_unit(unit_string); flex_type.has_value())
return Flex { numeric_value, flex_type.release_value() };
if (auto frequency_type = Frequency::unit_from_name(unit_string); frequency_type.has_value())
if (auto frequency_type = string_to_frequency_unit(unit_string); frequency_type.has_value())
return Frequency { numeric_value, frequency_type.release_value() };
if (auto resolution_type = Resolution::unit_from_name(unit_string); resolution_type.has_value())
if (auto resolution_type = string_to_resolution_unit(unit_string); resolution_type.has_value())
return Resolution { numeric_value, resolution_type.release_value() };
if (auto time_type = Time::unit_from_name(unit_string); time_type.has_value())
if (auto time_type = string_to_time_unit(unit_string); time_type.has_value())
return Time { numeric_value, time_type.release_value() };
}
@ -1027,7 +1027,7 @@ RefPtr<StyleValue const> Parser::parse_angle_value(TokenStream<ComponentValue>&
if (tokens.next_token().is(Token::Type::Dimension)) {
auto transaction = tokens.begin_transaction();
auto& dimension_token = tokens.consume_a_token().token();
if (auto angle_type = Angle::unit_from_name(dimension_token.dimension_unit()); angle_type.has_value()) {
if (auto angle_type = string_to_angle_unit(dimension_token.dimension_unit()); angle_type.has_value()) {
transaction.commit();
return AngleStyleValue::create(Angle { (dimension_token.dimension_value()), angle_type.release_value() });
}
@ -1058,7 +1058,7 @@ RefPtr<StyleValue const> Parser::parse_angle_percentage_value(TokenStream<Compon
if (tokens.next_token().is(Token::Type::Dimension)) {
auto transaction = tokens.begin_transaction();
auto& dimension_token = tokens.consume_a_token().token();
if (auto angle_type = Angle::unit_from_name(dimension_token.dimension_unit()); angle_type.has_value()) {
if (auto angle_type = string_to_angle_unit(dimension_token.dimension_unit()); angle_type.has_value()) {
transaction.commit();
return AngleStyleValue::create(Angle { (dimension_token.dimension_value()), angle_type.release_value() });
}
@ -1092,7 +1092,7 @@ RefPtr<StyleValue const> Parser::parse_flex_value(TokenStream<ComponentValue>& t
if (tokens.next_token().is(Token::Type::Dimension)) {
auto transaction = tokens.begin_transaction();
auto& dimension_token = tokens.consume_a_token().token();
if (auto flex_type = Flex::unit_from_name(dimension_token.dimension_unit()); flex_type.has_value()) {
if (auto flex_type = string_to_flex_unit(dimension_token.dimension_unit()); flex_type.has_value()) {
transaction.commit();
return FlexStyleValue::create(Flex { (dimension_token.dimension_value()), flex_type.release_value() });
}
@ -1114,7 +1114,7 @@ RefPtr<StyleValue const> Parser::parse_frequency_value(TokenStream<ComponentValu
if (tokens.next_token().is(Token::Type::Dimension)) {
auto transaction = tokens.begin_transaction();
auto& dimension_token = tokens.consume_a_token().token();
if (auto frequency_type = Frequency::unit_from_name(dimension_token.dimension_unit()); frequency_type.has_value()) {
if (auto frequency_type = string_to_frequency_unit(dimension_token.dimension_unit()); frequency_type.has_value()) {
transaction.commit();
return FrequencyStyleValue::create(Frequency { (dimension_token.dimension_value()), frequency_type.release_value() });
}
@ -1136,7 +1136,7 @@ RefPtr<StyleValue const> Parser::parse_frequency_percentage_value(TokenStream<Co
if (tokens.next_token().is(Token::Type::Dimension)) {
auto transaction = tokens.begin_transaction();
auto& dimension_token = tokens.consume_a_token().token();
if (auto frequency_type = Frequency::unit_from_name(dimension_token.dimension_unit()); frequency_type.has_value()) {
if (auto frequency_type = string_to_frequency_unit(dimension_token.dimension_unit()); frequency_type.has_value()) {
transaction.commit();
return FrequencyStyleValue::create(Frequency { (dimension_token.dimension_value()), frequency_type.release_value() });
}
@ -1161,7 +1161,7 @@ RefPtr<StyleValue const> Parser::parse_length_value(TokenStream<ComponentValue>&
if (tokens.next_token().is(Token::Type::Dimension)) {
auto transaction = tokens.begin_transaction();
auto& dimension_token = tokens.consume_a_token().token();
if (auto length_type = Length::unit_from_name(dimension_token.dimension_unit()); length_type.has_value()) {
if (auto length_type = string_to_length_unit(dimension_token.dimension_unit()); length_type.has_value()) {
transaction.commit();
return LengthStyleValue::create(Length { (dimension_token.dimension_value()), length_type.release_value() });
}
@ -1208,7 +1208,7 @@ RefPtr<StyleValue const> Parser::parse_length_percentage_value(TokenStream<Compo
if (tokens.next_token().is(Token::Type::Dimension)) {
auto transaction = tokens.begin_transaction();
auto& dimension_token = tokens.consume_a_token().token();
if (auto length_type = Length::unit_from_name(dimension_token.dimension_unit()); length_type.has_value()) {
if (auto length_type = string_to_length_unit(dimension_token.dimension_unit()); length_type.has_value()) {
transaction.commit();
return LengthStyleValue::create(Length { (dimension_token.dimension_value()), length_type.release_value() });
}
@ -1263,7 +1263,7 @@ RefPtr<StyleValue const> Parser::parse_resolution_value(TokenStream<ComponentVal
// https://drafts.csswg.org/css-values-4/#resolution
if (dimension_token.dimension_value() < 0)
return nullptr;
if (auto resolution_type = Resolution::unit_from_name(dimension_token.dimension_unit()); resolution_type.has_value()) {
if (auto resolution_type = string_to_resolution_unit(dimension_token.dimension_unit()); resolution_type.has_value()) {
transaction.commit();
return ResolutionStyleValue::create(Resolution { (dimension_token.dimension_value()), resolution_type.release_value() });
}
@ -1285,7 +1285,7 @@ RefPtr<StyleValue const> Parser::parse_time_value(TokenStream<ComponentValue>& t
if (tokens.next_token().is(Token::Type::Dimension)) {
auto transaction = tokens.begin_transaction();
auto& dimension_token = tokens.consume_a_token().token();
if (auto time_type = Time::unit_from_name(dimension_token.dimension_unit()); time_type.has_value()) {
if (auto time_type = string_to_time_unit(dimension_token.dimension_unit()); time_type.has_value()) {
transaction.commit();
return TimeStyleValue::create(Time { (dimension_token.dimension_value()), time_type.release_value() });
}
@ -1307,7 +1307,7 @@ RefPtr<StyleValue const> Parser::parse_time_percentage_value(TokenStream<Compone
if (tokens.next_token().is(Token::Type::Dimension)) {
auto transaction = tokens.begin_transaction();
auto& dimension_token = tokens.consume_a_token().token();
if (auto time_type = Time::unit_from_name(dimension_token.dimension_unit()); time_type.has_value()) {
if (auto time_type = string_to_time_unit(dimension_token.dimension_unit()); time_type.has_value()) {
transaction.commit();
return TimeStyleValue::create(Time { (dimension_token.dimension_value()), time_type.release_value() });
}
@ -4228,13 +4228,13 @@ RefPtr<CalculationNode const> Parser::convert_to_calculation_node(CalcParsing::N
auto numeric_value = component_value->token().dimension_value();
auto unit_string = component_value->token().dimension_unit();
if (auto length_type = Length::unit_from_name(unit_string); length_type.has_value())
if (auto length_type = string_to_length_unit(unit_string); length_type.has_value())
return NumericCalculationNode::create(Length { numeric_value, length_type.release_value() }, context);
if (auto angle_type = Angle::unit_from_name(unit_string); angle_type.has_value())
if (auto angle_type = string_to_angle_unit(unit_string); angle_type.has_value())
return NumericCalculationNode::create(Angle { numeric_value, angle_type.release_value() }, context);
if (auto flex_type = Flex::unit_from_name(unit_string); flex_type.has_value()) {
if (auto flex_type = string_to_flex_unit(unit_string); flex_type.has_value()) {
// https://www.w3.org/TR/css3-grid-layout/#fr-unit
// NOTE: <flex> values are not <length>s (nor are they compatible with <length>s, like some <percentage> values),
// so they cannot be represented in or combined with other unit types in calc() expressions.
@ -4247,13 +4247,13 @@ RefPtr<CalculationNode const> Parser::convert_to_calculation_node(CalcParsing::N
return nullptr;
}
if (auto frequency_type = Frequency::unit_from_name(unit_string); frequency_type.has_value())
if (auto frequency_type = string_to_frequency_unit(unit_string); frequency_type.has_value())
return NumericCalculationNode::create(Frequency { numeric_value, frequency_type.release_value() }, context);
if (auto resolution_type = Resolution::unit_from_name(unit_string); resolution_type.has_value())
if (auto resolution_type = string_to_resolution_unit(unit_string); resolution_type.has_value())
return NumericCalculationNode::create(Resolution { numeric_value, resolution_type.release_value() }, context);
if (auto time_type = Time::unit_from_name(unit_string); time_type.has_value())
if (auto time_type = string_to_time_unit(unit_string); time_type.has_value())
return NumericCalculationNode::create(Time { numeric_value, time_type.release_value() }, context);
ErrorReporter::the().report(InvalidValueError {

View file

@ -10,15 +10,15 @@
namespace Web::CSS {
Resolution::Resolution(double value, Type type)
: m_type(type)
Resolution::Resolution(double value, ResolutionUnit unit)
: m_unit(unit)
, m_value(value)
{
}
Resolution Resolution::make_dots_per_pixel(double value)
{
return { value, Type::Dppx };
return { value, ResolutionUnit::Dppx };
}
String Resolution::to_string(SerializationMode serialization_mode) const
@ -42,44 +42,16 @@ String Resolution::to_string(SerializationMode serialization_mode) const
double Resolution::to_dots_per_pixel() const
{
switch (m_type) {
case Type::Dpi:
switch (m_unit) {
case ResolutionUnit::Dpi:
return m_value / 96; // 1in = 2.54cm = 96px
case Type::Dpcm:
case ResolutionUnit::Dpcm:
return m_value / (96.0 / 2.54); // 1cm = 96px/2.54
case Type::Dppx:
case Type::X:
case ResolutionUnit::Dppx:
case ResolutionUnit::X:
return m_value;
}
VERIFY_NOT_REACHED();
}
StringView Resolution::unit_name() const
{
switch (m_type) {
case Type::Dpi:
return "dpi"sv;
case Type::Dpcm:
return "dpcm"sv;
case Type::Dppx:
return "dppx"sv;
case Type::X:
return "x"sv;
}
VERIFY_NOT_REACHED();
}
Optional<Resolution::Type> Resolution::unit_from_name(StringView name)
{
if (name.equals_ignoring_ascii_case("dpi"sv))
return Type::Dpi;
if (name.equals_ignoring_ascii_case("dpcm"sv))
return Type::Dpcm;
if (name.equals_ignoring_ascii_case("dppx"sv))
return Type::Dppx;
if (name.equals_ignoring_ascii_case("x"sv))
return Type::X;
return {};
}
}

View file

@ -8,33 +8,25 @@
#include <AK/String.h>
#include <LibWeb/CSS/SerializationMode.h>
#include <LibWeb/CSS/Units.h>
namespace Web::CSS {
class Resolution {
public:
enum class Type : u8 {
Dpi,
Dpcm,
Dppx,
X,
};
static Optional<Type> unit_from_name(StringView);
Resolution(double value, Type type);
Resolution(double value, ResolutionUnit unit);
static Resolution make_dots_per_pixel(double);
String to_string(SerializationMode = SerializationMode::Normal) const;
double to_dots_per_pixel() const;
Type type() const { return m_type; }
double raw_value() const { return m_value; }
StringView unit_name() const;
ResolutionUnit unit() const { return m_unit; }
StringView unit_name() const { return CSS::to_string(m_unit); }
bool operator==(Resolution const& other) const
{
return m_type == other.m_type && m_value == other.m_value;
return m_unit == other.m_unit && m_value == other.m_value;
}
int operator<=>(Resolution const& other) const
@ -50,7 +42,7 @@ public:
}
private:
Type m_type;
ResolutionUnit m_unit;
double m_value { 0 };
};

View file

@ -1132,7 +1132,7 @@ static void apply_animation_properties(DOM::Document& document, CascadedProperti
}
}
CSS::Time delay { 0, CSS::Time::Type::S };
auto delay = Time::make_seconds(0);
if (auto delay_value = cascaded_properties.property(PropertyID::AnimationDelay); delay_value) {
if (delay_value->is_time()) {
delay = delay_value->as_time().time();

View file

@ -178,25 +178,25 @@ static CalculationNode::NumericValue clamp_and_censor_numeric_value(NumericCalcu
return Number { value.type(), clamp_and_censor(context.resolve_numbers_as_integers ? value.integer_value() : value.value(), accepted_range->min, accepted_range->max) };
},
[&](Angle const& value) -> CalculationNode::NumericValue {
return Angle { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.type() };
return Angle { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.unit() };
},
[&](Flex const& value) -> CalculationNode::NumericValue {
return Flex { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.type() };
return Flex { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.unit() };
},
[&](Frequency const& value) -> CalculationNode::NumericValue {
return Frequency { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.type() };
return Frequency { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.unit() };
},
[&](Length const& value) -> CalculationNode::NumericValue {
return Length { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.type() };
return Length { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.unit() };
},
[&](Percentage const& value) -> CalculationNode::NumericValue {
return Percentage { clamp_and_censor(value.value(), accepted_range->min, accepted_range->max) };
},
[&](Resolution const& value) -> CalculationNode::NumericValue {
return Resolution { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.type() };
return Resolution { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.unit() };
},
[&](Time const& value) -> CalculationNode::NumericValue {
return Time { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.type() };
return Time { clamp_and_censor(value.raw_value(), accepted_range->min, accepted_range->max), value.unit() };
});
}
@ -689,14 +689,14 @@ bool NumericCalculationNode::contains_percentage() const
bool NumericCalculationNode::is_in_canonical_unit() const
{
return m_value.visit(
[](Angle const& angle) { return angle.type() == Angle::Type::Deg; },
[](Flex const& flex) { return flex.type() == Flex::Type::Fr; },
[](Frequency const& frequency) { return frequency.type() == Frequency::Type::Hz; },
[](Length const& length) { return length.type() == Length::Type::Px; },
[](Angle const& angle) { return angle.unit() == AngleUnit::Deg; },
[](Flex const& flex) { return flex.unit() == FlexUnit::Fr; },
[](Frequency const& frequency) { return frequency.unit() == FrequencyUnit::Hz; },
[](Length const& length) { return length.unit() == LengthUnit::Px; },
[](Number const&) { return true; },
[](Percentage const&) { return true; },
[](Resolution const& resolution) { return resolution.type() == Resolution::Type::Dppx; },
[](Time const& time) { return time.type() == Time::Type::S; });
[](Resolution const& resolution) { return resolution.unit() == ResolutionUnit::Dppx; },
[](Time const& time) { return time.unit() == TimeUnit::S; });
}
static Optional<CalculatedStyleValue::CalculationResult> try_get_value_with_canonical_unit(CalculationNode const& child, CalculationContext const& context, CalculationResolutionContext const& resolution_context)
@ -807,7 +807,7 @@ NonnullRefPtr<NumericCalculationNode const> NumericCalculationNode::negated(Calc
return create(Number(number.type(), -number.value()), context);
},
[&]<typename T>(T const& value) {
return create(T(-value.raw_value(), value.type()), context);
return create(T(-value.raw_value(), value.unit()), context);
});
}
@ -3157,7 +3157,7 @@ static Optional<NumericChildAndIndex> find_numeric_child_with_same_unit(Vector<N
return target.value().has<Number>();
},
[&]<typename T>(T const& value) {
if (auto const* other = target.value().get_pointer<T>(); other && other->type() == value.type()) {
if (auto const* other = target.value().get_pointer<T>(); other && other->unit() == value.unit()) {
return true;
}
return false;
@ -3213,19 +3213,19 @@ NonnullRefPtr<CalculationNode const> simplify_a_calculation_tree(CalculationNode
[](Empty const&) -> RefPtr<NumericCalculationNode const> { return nullptr; },
[&](Angle const& angle) -> RefPtr<NumericCalculationNode const> {
VERIFY(context.percentages_resolve_as == ValueType::Angle);
if (angle.type() == Angle::Type::Deg)
if (angle.unit() == AngleUnit::Deg)
return NumericCalculationNode::create(angle.percentage_of(*percentage), context);
return NumericCalculationNode::create(Angle::make_degrees(angle.to_degrees()).percentage_of(*percentage), context);
},
[&](Frequency const& frequency) -> RefPtr<NumericCalculationNode const> {
VERIFY(context.percentages_resolve_as == ValueType::Frequency);
if (frequency.type() == Frequency::Type::Hz)
if (frequency.unit() == FrequencyUnit::Hz)
return NumericCalculationNode::create(frequency.percentage_of(*percentage), context);
return NumericCalculationNode::create(Frequency::make_hertz(frequency.to_hertz()).percentage_of(*percentage), context);
},
[&](Length const& length) -> RefPtr<NumericCalculationNode const> {
VERIFY(context.percentages_resolve_as == ValueType::Length);
if (length.type() == Length::Type::Px)
if (length.unit() == LengthUnit::Px)
return NumericCalculationNode::create(length.percentage_of(*percentage), context);
if (length.is_absolute())
return NumericCalculationNode::create(Length::make_px(length.absolute_length_to_px()).percentage_of(*percentage), context);
@ -3235,7 +3235,7 @@ NonnullRefPtr<CalculationNode const> simplify_a_calculation_tree(CalculationNode
},
[&](Time const& time) -> RefPtr<NumericCalculationNode const> {
VERIFY(context.percentages_resolve_as == ValueType::Time);
if (time.type() == Time::Type::S)
if (time.unit() == TimeUnit::S)
return NumericCalculationNode::create(time.percentage_of(*percentage), context);
return NumericCalculationNode::create(Time::make_seconds(time.to_seconds()).percentage_of(*percentage), context);
});
@ -3250,22 +3250,22 @@ NonnullRefPtr<CalculationNode const> simplify_a_calculation_tree(CalculationNode
// NOTE: We use nullptr here to signify "use the original".
RefPtr<CalculationNode const> resolved = root_numeric.value().visit(
[&](Angle const& angle) -> RefPtr<CalculationNode const> {
if (angle.type() == Angle::Type::Deg)
if (angle.unit() == AngleUnit::Deg)
return nullptr;
return NumericCalculationNode::create(Angle::make_degrees(angle.to_degrees()), context);
},
[&](Flex const& flex) -> RefPtr<CalculationNode const> {
if (flex.type() == Flex::Type::Fr)
if (flex.unit() == FlexUnit::Fr)
return nullptr;
return NumericCalculationNode::create(Flex::make_fr(flex.to_fr()), context);
},
[&](Frequency const& frequency) -> RefPtr<CalculationNode const> {
if (frequency.type() == Frequency::Type::Hz)
if (frequency.unit() == FrequencyUnit::Hz)
return nullptr;
return NumericCalculationNode::create(Frequency::make_hertz(frequency.to_hertz()), context);
},
[&](Length const& length) -> RefPtr<CalculationNode const> {
if (length.type() == Length::Type::Px)
if (length.unit() == LengthUnit::Px)
return nullptr;
if (length.is_absolute())
return NumericCalculationNode::create(Length::make_px(length.absolute_length_to_px()), context);
@ -3280,12 +3280,12 @@ NonnullRefPtr<CalculationNode const> simplify_a_calculation_tree(CalculationNode
return nullptr;
},
[&](Resolution const& resolution) -> RefPtr<CalculationNode const> {
if (resolution.type() == Resolution::Type::Dppx)
if (resolution.unit() == ResolutionUnit::Dppx)
return nullptr;
return NumericCalculationNode::create(Resolution::make_dots_per_pixel(resolution.to_dots_per_pixel()), context);
},
[&](Time const& time) -> RefPtr<CalculationNode const> {
if (time.type() == Time::Type::S)
if (time.unit() == TimeUnit::S)
return nullptr;
return NumericCalculationNode::create(Time::make_seconds(time.to_seconds()), context);
});
@ -3461,7 +3461,7 @@ NonnullRefPtr<CalculationNode const> simplify_a_calculation_tree(CalculationNode
return NumericCalculationNode::create(Number(Number::Type::Number, number.value() + child_numeric.value().get<Number>().value()), context);
},
[&]<typename T>(T const& value) {
return NumericCalculationNode::create(T(value.raw_value() + child_numeric.value().get<T>().raw_value(), value.type()), context);
return NumericCalculationNode::create(T(value.raw_value() + child_numeric.value().get<T>().raw_value(), value.unit()), context);
});
summed_children[existing_child_and_index->index] = move(new_value);
} else {
@ -3543,7 +3543,17 @@ NonnullRefPtr<CalculationNode const> simplify_a_calculation_tree(CalculationNode
all_numeric = false;
break;
}
multiplied_children.append(as<NumericCalculationNode>(*sum_child).value().visit([&](Percentage const& percentage) { return NumericCalculationNode::create(Percentage(percentage.value() * multiplier->value()), context); }, [&](Number const& number) { return NumericCalculationNode::create(Number(Number::Type::Number, number.value() * multiplier->value()), context); }, [&]<typename T>(T const& value) { return NumericCalculationNode::create(T(value.raw_value() * multiplier->value(), value.type()), context); }));
auto& child_value = as<NumericCalculationNode>(*sum_child).value();
multiplied_children.append(child_value.visit(
[&](Percentage const& percentage) {
return NumericCalculationNode::create(Percentage(percentage.value() * multiplier->value()), context);
},
[&](Number const& number) {
return NumericCalculationNode::create(Number(Number::Type::Number, number.value() * multiplier->value()), context);
},
[&]<typename T>(T const& value) {
return NumericCalculationNode::create(T(value.raw_value() * multiplier->value(), value.unit()), context);
}));
}
if (all_numeric)

View file

@ -10,20 +10,20 @@
namespace Web::CSS {
Time::Time(double value, Type type)
: m_type(type)
Time::Time(double value, TimeUnit unit)
: m_unit(unit)
, m_value(value)
{
}
Time Time::make_seconds(double value)
{
return { value, Type::S };
return { value, TimeUnit::S };
}
Time Time::percentage_of(Percentage const& percentage) const
{
return Time { percentage.as_fraction() * m_value, m_type };
return Time { percentage.as_fraction() * m_value, m_unit };
}
String Time::to_string(SerializationMode serialization_mode) const
@ -47,10 +47,10 @@ String Time::to_string(SerializationMode serialization_mode) const
double Time::to_seconds() const
{
switch (m_type) {
case Type::S:
switch (m_unit) {
case TimeUnit::S:
return m_value;
case Type::Ms:
case TimeUnit::Ms:
return m_value / 1000.0;
}
VERIFY_NOT_REACHED();
@ -58,36 +58,15 @@ double Time::to_seconds() const
double Time::to_milliseconds() const
{
switch (m_type) {
case Type::S:
switch (m_unit) {
case TimeUnit::S:
return m_value * 1000.0;
case Type::Ms:
case TimeUnit::Ms:
return m_value;
}
VERIFY_NOT_REACHED();
}
StringView Time::unit_name() const
{
switch (m_type) {
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_ascii_case("s"sv)) {
return Type::S;
} else if (name.equals_ignoring_ascii_case("ms"sv)) {
return Type::Ms;
}
return {};
}
Time Time::resolve_calculated(NonnullRefPtr<CalculatedStyleValue const> const& calculated, Layout::Node const& layout_node, Time const& reference_value)
{
CalculationResolutionContext context {

View file

@ -8,20 +8,14 @@
#include <AK/String.h>
#include <LibWeb/CSS/SerializationMode.h>
#include <LibWeb/CSS/Units.h>
#include <LibWeb/Forward.h>
namespace Web::CSS {
class Time {
public:
enum class Type : u8 {
S,
Ms,
};
static Optional<Type> unit_from_name(StringView);
Time(double value, Type type);
Time(double value, TimeUnit unit);
static Time make_seconds(double);
Time percentage_of(Percentage const&) const;
@ -29,13 +23,13 @@ public:
double to_milliseconds() const;
double to_seconds() const;
Type type() const { return m_type; }
double raw_value() const { return m_value; }
StringView unit_name() const;
TimeUnit unit() const { return m_unit; }
StringView unit_name() const { return CSS::to_string(m_unit); }
bool operator==(Time const& other) const
{
return m_type == other.m_type && m_value == other.m_value;
return m_unit == other.m_unit && m_value == other.m_value;
}
int operator<=>(Time const& other) const
@ -53,7 +47,7 @@ public:
static Time resolve_calculated(NonnullRefPtr<CalculatedStyleValue const> const&, Layout::Node const&, Time const& reference_value);
private:
Type m_type;
TimeUnit m_unit;
double m_value { 0 };
};

View file

@ -143,7 +143,7 @@ void HTMLInputElement::adjust_computed_style(CSS::ComputedProperties& style)
if (type_state() != TypeAttributeState::FileUpload) {
if (style.property(CSS::PropertyID::Width).has_auto())
style.set_property(CSS::PropertyID::Width, CSS::LengthStyleValue::create(CSS::Length(size(), CSS::Length::Type::Ch)));
style.set_property(CSS::PropertyID::Width, CSS::LengthStyleValue::create(CSS::Length(size(), CSS::LengthUnit::Ch)));
}
// NOTE: Other browsers apply a minimum height of a single line's line-height to single-line input elements.

View file

@ -53,9 +53,9 @@ void HTMLTextAreaElement::adjust_computed_style(CSS::ComputedProperties& style)
style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::InlineBlock)));
if (style.property(CSS::PropertyID::Width).has_auto())
style.set_property(CSS::PropertyID::Width, CSS::LengthStyleValue::create(CSS::Length(cols(), CSS::Length::Type::Ch)));
style.set_property(CSS::PropertyID::Width, CSS::LengthStyleValue::create(CSS::Length(cols(), CSS::LengthUnit::Ch)));
if (style.property(CSS::PropertyID::Height).has_auto())
style.set_property(CSS::PropertyID::Height, CSS::LengthStyleValue::create(CSS::Length(rows(), CSS::Length::Type::Lh)));
style.set_property(CSS::PropertyID::Height, CSS::LengthStyleValue::create(CSS::Length(rows(), CSS::LengthUnit::Lh)));
}
void HTMLTextAreaElement::initialize(JS::Realm& realm)

View file

@ -407,7 +407,7 @@ Optional<CSS::MediaFeatureValue> Window::query_media_feature(CSS::MediaFeatureID
// FIXME: Make this a preference
return CSS::MediaFeatureValue(CSS::Keyword::NoPreference);
case CSS::MediaFeatureID::Resolution:
return CSS::MediaFeatureValue(CSS::Resolution(device_pixel_ratio(), CSS::Resolution::Type::Dppx));
return CSS::MediaFeatureValue(CSS::Resolution::make_dots_per_pixel(device_pixel_ratio()));
case CSS::MediaFeatureID::Scan:
// FIXME: Detect this from the display, if we can. Most displays aren't scanning and should return None.
return CSS::MediaFeatureValue(CSS::Keyword::None);

View file

@ -342,7 +342,7 @@ Optional<Vector<CSS::LengthPercentage>> IntersectionObserver::parse_a_margin(JS:
for (auto const& token : tokens) {
// If token is an absolute length dimension token, replace it with a an equivalent pixel length.
if (token.is(CSS::Parser::Token::Type::Dimension)) {
auto length = CSS::Length(token.token().dimension_value(), CSS::Length::unit_from_name(token.token().dimension_unit()).value());
auto length = CSS::Length(token.token().dimension_value(), CSS::string_to_length_unit(token.token().dimension_unit()).value());
if (length.is_absolute()) {
length.absolute_length_to_px();
tokens_length_percentage.append(length);

View file

@ -126,7 +126,7 @@ LinearGradientData resolve_linear_gradient_data(Layout::NodeWithStyle const& nod
ConicGradientData resolve_conic_gradient_data(Layout::NodeWithStyle const& node, CSS::ConicGradientStyleValue const& conic_gradient)
{
CSS::Angle one_turn(360.0f, CSS::Angle::Type::Deg);
CSS::Angle one_turn(360.0f, CSS::AngleUnit::Deg);
auto resolved_color_stops = resolve_color_stop_positions(
node, conic_gradient.color_stop_list(), [&](auto const& angle_percentage) {
return angle_percentage.resolved(node, one_turn).to_degrees() / one_turn.to_degrees();

View file

@ -1589,7 +1589,7 @@ void PaintableWithLines::resolve_paint_properties()
return max(glyph_height.scaled(0.1), 1);
},
[&](CSS::LengthPercentage const& length_percentage) {
auto resolved_length = length_percentage.resolved(text_node, CSS::Length(1, CSS::Length::Type::Em).to_px(text_node)).to_px(*fragment.m_layout_node);
auto resolved_length = length_percentage.resolved(text_node, CSS::Length(1, CSS::LengthUnit::Em).to_px(text_node)).to_px(*fragment.m_layout_node);
return max(resolved_length, 1);
});
}();

View file

@ -29,22 +29,22 @@ GC::Ref<SVGLength> SVGLength::from_length_percentage(JS::Realm& realm, CSS::Leng
if (length_percentage.is_length())
return create(
realm, [&] {
switch (length_percentage.length().type()) {
case CSS::Length::Type::Em:
switch (length_percentage.length().unit()) {
case CSS::LengthUnit::Em:
return SVG_LENGTHTYPE_EMS;
case CSS::Length::Type::Ex:
case CSS::LengthUnit::Ex:
return SVG_LENGTHTYPE_EXS;
case CSS::Length::Type::Px:
case CSS::LengthUnit::Px:
return SVG_LENGTHTYPE_PX;
case CSS::Length::Type::Cm:
case CSS::LengthUnit::Cm:
return SVG_LENGTHTYPE_CM;
case CSS::Length::Type::Mm:
case CSS::LengthUnit::Mm:
return SVG_LENGTHTYPE_MM;
case CSS::Length::Type::In:
case CSS::LengthUnit::In:
return SVG_LENGTHTYPE_IN;
case CSS::Length::Type::Pt:
case CSS::LengthUnit::Pt:
return SVG_LENGTHTYPE_PT;
case CSS::Length::Type::Pc:
case CSS::LengthUnit::Pc:
return SVG_LENGTHTYPE_PC;
default:
return SVG_LENGTHTYPE_UNKNOWN;

View file

@ -300,7 +300,7 @@ ErrorOr<void> ViewTransition::capture_the_old_state()
// 6. Set captures old transform to a <transform-function> that would map elements border box from the
// snapshot containing block origin to its current visual position.
// FIXME: Actually compute the right transform here.
capture->old_transform = CSS::Transformation(CSS::TransformFunction::Translate, Vector<CSS::TransformValue>({ CSS::TransformValue(CSS::Length(0, CSS::Length::Type::Px)), CSS::TransformValue(CSS::Length(0, CSS::Length::Type::Px)) }));
capture->old_transform = CSS::Transformation(CSS::TransformFunction::Translate, Vector<CSS::TransformValue>({ CSS::TransformValue(CSS::Length(0, CSS::LengthUnit::Px)), CSS::TransformValue(CSS::Length(0, CSS::LengthUnit::Px)) }));
// 7. Set captures old writing-mode to the computed value of writing-mode on element.
capture->old_writing_mode = element.layout_node()->computed_values().writing_mode();