diff --git a/AK/String.h b/AK/String.h index 4e007cffc152..7c4c10669abf 100644 --- a/AK/String.h +++ b/AK/String.h @@ -57,6 +57,31 @@ class String : public Detail::StringBase { [[nodiscard]] static String from_utf8_without_validation(ReadonlyBytes); [[nodiscard]] static String from_ascii_without_validation(ReadonlyBytes); + // NB: These round-trip the one-word raw representation through FFI bridges (e.g. the LibWeb + // Rust style value data), which retain the raw value and manage its reference manually. + // to_raw_leaked() leaks one reference to the bridge, from_raw() reconstructs a string + // without consuming the bridge's reference, and unref_raw() releases it. + [[nodiscard]] FlatPtr to_raw_leaked() const + { + if (!is_short_string()) + data_without_union_member_assertion()->ref(); + return raw({}); + } + + [[nodiscard]] static String from_raw(FlatPtr raw) + { + auto string = adopt_raw(raw); + if (!string.is_short_string()) + string.data_without_union_member_assertion()->ref(); + return string; + } + + static void unref_raw(FlatPtr raw) + { + // Adopt the bridge's reference and let it drop. + auto string = adopt_raw(raw); + } + [[nodiscard]] static constexpr String from_ascii_short_string_without_validation(char const* data, size_t length) { VERIFY(length <= Detail::MAX_SHORT_STRING_BYTE_COUNT); @@ -231,6 +256,16 @@ class String : public Detail::StringBase { using ShortString = Detail::ShortString; + // Adopts a raw value previously produced by to_raw_leaked(), together with ownership of one + // reference to its data if it is not a short string. + [[nodiscard]] static String adopt_raw(FlatPtr raw) + { + String string; + auto const** data = __builtin_launder(&string.m_impl.data); + *data = bit_cast(raw); + return string; + } + constexpr bool is_invalid() const { return raw(Badge {}) == 0; diff --git a/AK/Utf16FlyString.h b/AK/Utf16FlyString.h index e81fdd47fd16..72bc54969b09 100644 --- a/AK/Utf16FlyString.h +++ b/AK/Utf16FlyString.h @@ -30,6 +30,34 @@ class [[nodiscard]] Utf16FlyString { static Utf16FlyString from_utf16(Utf16View const&); + // NB: These round-trip the one-word raw representation through FFI bridges (e.g. the LibWeb + // Rust style value data), which retain the raw value and manage its reference manually. + // to_raw_leaked() leaks one reference to the bridge, from_raw() reconstructs a fly string + // without consuming the bridge's reference, and unref_raw() releases it. + [[nodiscard]] FlatPtr to_raw_leaked() const + { + if (m_data.has_long_storage()) + m_data.data({})->ref(); + return m_data.raw({}); + } + + [[nodiscard]] static Utf16FlyString from_raw(FlatPtr raw) + { + auto base = Detail::Utf16StringBase::adopt_raw({}, raw); + if (base.has_long_storage()) + base.data({})->ref(); + + Utf16FlyString string; + string.m_data = move(base); + return string; + } + + static void unref_raw(FlatPtr raw) + { + // Adopt the bridge's reference and let it drop. + auto base = Detail::Utf16StringBase::adopt_raw({}, raw); + } + template requires(IsOneOf, Utf16String, Utf16FlyString>) static Utf16FlyString from_utf16(T&&) = delete; diff --git a/AK/Utf16String.h b/AK/Utf16String.h index c294ced18322..9754c4d1a957 100644 --- a/AK/Utf16String.h +++ b/AK/Utf16String.h @@ -70,6 +70,26 @@ class [[nodiscard]] Utf16String : public Detail::Utf16StringBase { static Utf16String from_utf16(Utf16View const& utf16_string); + // NB: These round-trip the one-word raw representation through FFI bridges (e.g. the LibWeb + // Rust style value data); the bridge releases its reference through + // Utf16FlyString::unref_raw(), which handles any Utf16StringBase-backed string. + [[nodiscard]] FlatPtr to_raw_leaked() const + { + if (has_long_storage()) + data_without_union_member_assertion()->ref(); + return raw(); + } + + [[nodiscard]] static Utf16String from_raw(FlatPtr raw) + { + Utf16String string; + auto const** data = __builtin_launder(&string.m_value.data); + *data = bit_cast(raw); + if (string.has_long_storage()) + string.data_without_union_member_assertion()->ref(); + return string; + } + template requires(IsOneOf, Utf16String, Utf16FlyString>) static Utf16String from_utf16(T&&) = delete; diff --git a/AK/Utf16StringBase.h b/AK/Utf16StringBase.h index d434a483aad5..2bad49dc3b16 100644 --- a/AK/Utf16StringBase.h +++ b/AK/Utf16StringBase.h @@ -341,6 +341,17 @@ class Utf16StringBase { [[nodiscard]] constexpr FlatPtr raw(Badge) const { return raw(); } + // NB: Adopts a raw value previously produced by raw(), together with ownership of one + // reference to its data if it has long storage. For FFI bridges that retain the raw + // representation of a string. + [[nodiscard]] ALWAYS_INLINE static Utf16StringBase adopt_raw(Badge, FlatPtr raw) + { + Utf16StringBase string; + auto const** data = __builtin_launder(&string.m_value.data); + *data = bit_cast(raw); + return string; + } + protected: [[nodiscard]] constexpr FlatPtr raw() const { return bit_cast(m_value); } diff --git a/Libraries/LibSandbox/Seccomp.cpp b/Libraries/LibSandbox/Seccomp.cpp index 443adc0ba18d..a707bb7d1bda 100644 --- a/Libraries/LibSandbox/Seccomp.cpp +++ b/Libraries/LibSandbox/Seccomp.cpp @@ -184,6 +184,7 @@ static constexpr unsigned read_only_open_flags = O_CLOEXEC; #define IF_DEFINED_unlinkat(if_defined, if_not_defined) if_defined #define IF_DEFINED_umask(if_defined, if_not_defined) if_defined #define IF_DEFINED_uname(if_defined, if_not_defined) if_defined +#define IF_DEFINED_utimensat(if_defined, if_not_defined) if_defined #define IF_DEFINED_wait4(if_defined, if_not_defined) if_defined #define IF_DEFINED_waitid(if_defined, if_not_defined) if_defined #define IF_DEFINED_write(if_defined, if_not_defined) if_defined @@ -472,6 +473,10 @@ static constexpr unsigned read_only_open_flags = O_CLOEXEC; # undef IF_DEFINED_umask # define IF_DEFINED_umask(if_defined, if_not_defined) if_not_defined #endif +#ifndef __NR_utimensat +# undef IF_DEFINED_utimensat +# define IF_DEFINED_utimensat(if_defined, if_not_defined) if_not_defined +#endif #ifndef __NR_wait4 # undef IF_DEFINED_wait4 # define IF_DEFINED_wait4(if_defined, if_not_defined) if_not_defined @@ -685,6 +690,9 @@ static char const* syscall_name(long syscall_number) #endif #ifdef __NR_unlinkat CASE_SYSCALL_NAME(unlinkat); +#endif +#ifdef __NR_utimensat + CASE_SYSCALL_NAME(utimensat); #endif default: return "unknown"; @@ -855,6 +863,9 @@ void SeccompPolicy::allow_filesystem_writes() SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, fdatasync); SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, fallocate); SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, flock); + // NB: Mesa's shader disk cache updates entry mtimes for LRU eviction, and glibc routes the + // whole utime() family through utimensat() on modern kernels. + SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, utimensat); append(BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_fcntl, 0, 5)); append(SECCOMP_LOAD_ARGUMENT(1)); diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 57c9f0c0daf6..4b1c2214445b 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -1308,7 +1308,7 @@ endforeach() import_rust_crate( MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libweb_rust - FFI_HEADERS RustFFI.h SelectorRustFFI.h HTML/Parser/RustFFI.h + FFI_HEADERS RustFFI.h SelectorRustFFI.h StyleValueRustFFI.h HTML/Parser/RustFFI.h ) set(content_blocker_rust_features "") diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index ea48fe3668e0..6f935b89b627 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -231,9 +231,10 @@ RefPtr ComputedValues::computed_style_value(PropertyID propert auto filter_style_value = [](Filter const& filter) -> NonnullRefPtr { if (filter.is_none()) return KeywordStyleValue::create(Keyword::None); + auto filter_values = filter.filters(); StyleValueVector filters; - MUST(filters.try_ensure_capacity(filter.filters().size())); - for (auto const& filter_value : filter.filters()) + MUST(filters.try_ensure_capacity(filter_values.size())); + for (auto const& filter_value : filter_values) filters.unchecked_append(filter_value); return StyleValueList::create(move(filters), StyleValueList::Separator::Space, StyleValueList::Collapsible::No); }; @@ -2119,11 +2120,12 @@ PreferredColorScheme ComputedProperties::color_scheme(PreferredColorScheme prefe { // To determine the used color scheme of an element: auto const& scheme_value = property(PropertyID::ColorScheme).as_color_scheme(); + auto schemes = scheme_value.schemes(); // 1. If the user’s preferred color scheme, as indicated by the prefers-color-scheme media feature, // is present among the listed color schemes, and is supported by the user agent, // that’s the element’s used color scheme. - if (preferred_scheme != PreferredColorScheme::Auto && scheme_value.schemes().contains_slow(preferred_color_scheme_to_utf16_fly_string(preferred_scheme))) + if (preferred_scheme != PreferredColorScheme::Auto && schemes.contains_slow(preferred_color_scheme_to_utf16_fly_string(preferred_scheme))) return preferred_scheme; // 2. Otherwise, if the user has indicated an overriding preference for their chosen color scheme, @@ -2134,7 +2136,7 @@ PreferredColorScheme ComputedProperties::color_scheme(PreferredColorScheme prefe // 3. Otherwise, if the user agent supports at least one of the listed color schemes, // the used color scheme is the first supported color scheme in the list. - auto first_supported = scheme_value.schemes().first_matching([](auto scheme) { return preferred_color_scheme_from_string(scheme) != PreferredColorScheme::Auto; }); + auto first_supported = schemes.first_matching([](auto scheme) { return preferred_color_scheme_from_string(scheme) != PreferredColorScheme::Auto; }); if (first_supported.has_value()) return preferred_color_scheme_from_string(first_supported.value()); @@ -2515,7 +2517,7 @@ Vector ComputedProperties::mask_layers() const auto property_values = [&](PropertyID property_id) { auto const& value = property(property_id); if (value.is_value_list()) - return value.as_value_list().values(); + return StyleValueVector { value.as_value_list().values() }; return StyleValueVector { value }; }; @@ -3226,7 +3228,7 @@ Vector ComputedProperties::text_decoration_line() const if (value.is_value_list()) { Vector lines; - auto& values = value.as_value_list().values(); + auto values = value.as_value_list().values(); for (auto const& item : values) { lines.append(keyword_to_text_decoration_line(item->to_keyword()).value()); } @@ -3824,7 +3826,7 @@ Containment ComputedProperties::contain() const break; default: if (value.is_value_list()) { - auto& values = value.as_value_list().values(); + auto values = value.as_value_list().values(); for (auto const& item : values) { switch (item->to_keyword()) { case Keyword::Size: @@ -3862,7 +3864,7 @@ Vector ComputedProperties::container_name() const Vector names; if (value.is_value_list()) { - auto& values = value.as_value_list().values(); + auto values = value.as_value_list().values(); for (auto const& item : values) names.append(item->as_custom_ident().custom_ident()); } else { @@ -3882,7 +3884,7 @@ ContainerType ComputedProperties::container_type() const return container_type; if (value.is_value_list()) { - auto& values = value.as_value_list().values(); + auto values = value.as_value_list().values(); for (auto const& item : values) { switch (item->to_keyword()) { case Keyword::Size: @@ -4163,7 +4165,7 @@ Vector ComputedProperties::counter_data(PropertyID property_id) con auto const& value = property(property_id); if (value.is_counter_definitions()) { - auto& counter_definitions = value.as_counter_definitions().counter_definitions(); + auto counter_definitions = value.as_counter_definitions().counter_definitions(); Vector result; for (auto& counter : counter_definitions) { CounterData data { diff --git a/Libraries/LibWeb/CSS/ComputedValues.cpp b/Libraries/LibWeb/CSS/ComputedValues.cpp index 34d1890a3064..9c6e7ac29fcc 100644 --- a/Libraries/LibWeb/CSS/ComputedValues.cpp +++ b/Libraries/LibWeb/CSS/ComputedValues.cpp @@ -600,7 +600,8 @@ NonnullRefPtr ComputedValues::create(ComputedProperties co auto list_style_type = computed_style.list_style_type(style_scope); auto const& list_style_type_value = computed_style.property(PropertyID::ListStyleType); if (list_style_type_value.is_counter_style() && list_style_type_value.as_counter_style().value().has()) { - auto const& symbols = list_style_type_value.as_counter_style().value().get(); + auto counter_style_value = list_style_type_value.as_counter_style().value(); + auto const& symbols = counter_style_value.get(); auto counter_style = list_style_type.get>(); VERIFY(counter_style); list_style_type = ListStyleSymbols { diff --git a/Libraries/LibWeb/CSS/Filter.cpp b/Libraries/LibWeb/CSS/Filter.cpp index 7a9a10f9a5b5..8df07da10cb7 100644 --- a/Libraries/LibWeb/CSS/Filter.cpp +++ b/Libraries/LibWeb/CSS/Filter.cpp @@ -10,7 +10,7 @@ namespace Web::CSS { -StyleValueVector const& Filter::filters() const +StyleValueVector Filter::filters() const { VERIFY(has_filters()); return m_filter_value_list->values(); diff --git a/Libraries/LibWeb/CSS/Filter.h b/Libraries/LibWeb/CSS/Filter.h index d1ff362ad3d3..8a875165c737 100644 --- a/Libraries/LibWeb/CSS/Filter.h +++ b/Libraries/LibWeb/CSS/Filter.h @@ -26,7 +26,7 @@ class Filter { bool has_filters() const { return m_filter_value_list; } bool is_none() const { return !has_filters(); } - StyleValueVector const& filters() const; + StyleValueVector filters() const; private: RefPtr m_filter_value_list { nullptr }; diff --git a/Libraries/LibWeb/CSS/FontFace.cpp b/Libraries/LibWeb/CSS/FontFace.cpp index 5a6a204810f7..6ce84bacd005 100644 --- a/Libraries/LibWeb/CSS/FontFace.cpp +++ b/Libraries/LibWeb/CSS/FontFace.cpp @@ -62,7 +62,7 @@ static FontWeightRange compute_weight_range(StyleValue const& value) if (value.to_keyword() == Keyword::Auto || value.to_keyword() == Keyword::Normal) return { 400, 400 }; - auto& weight_values = value.as_value_list().values(); + auto weight_values = value.as_value_list().values(); if (weight_values.size() == 1) { auto one_weight = static_cast(StyleComputer::compute_font_weight(weight_values[0], {})->as_number().number()); return { one_weight, one_weight }; diff --git a/Libraries/LibWeb/CSS/GridTrackPlacement.h b/Libraries/LibWeb/CSS/GridTrackPlacement.h index 8df86e9827e5..eab906c1617a 100644 --- a/Libraries/LibWeb/CSS/GridTrackPlacement.h +++ b/Libraries/LibWeb/CSS/GridTrackPlacement.h @@ -54,6 +54,7 @@ class GridTrackPlacement { NonnullRefPtr line_number() const { return *m_value.get().line_number; } NonnullRefPtr span() const { return *m_value.get().value; } + Optional const& span_name() const { return m_value.get().name; } void serialize(StringBuilder&, SerializationMode) const; String to_string(SerializationMode mode) const; diff --git a/Libraries/LibWeb/CSS/GridTrackSize.h b/Libraries/LibWeb/CSS/GridTrackSize.h index 0c6dd74dfd83..a208e45099bb 100644 --- a/Libraries/LibWeb/CSS/GridTrackSize.h +++ b/Libraries/LibWeb/CSS/GridTrackSize.h @@ -125,6 +125,7 @@ class GridTrackSizeList { Vector track_list() const; auto const& list() const { return m_list; } bool is_subgrid() const { return m_is_subgrid; } + bool preserves_line_name_sets() const { return m_preserve_line_name_sets; } void serialize(StringBuilder&, SerializationMode) const; String to_string(SerializationMode) const; @@ -170,6 +171,7 @@ class GridRepeat { return int_from_style_value(*m_repeat_count); } GridTrackSizeList const& grid_track_size_list() const& { return m_grid_track_size_list; } + RefPtr repeat_count_style_value() const { return m_repeat_count; } GridRepeatType type() const& { return m_type; } void serialize(StringBuilder&, SerializationMode) const; diff --git a/Libraries/LibWeb/CSS/Interpolation.cpp b/Libraries/LibWeb/CSS/Interpolation.cpp index ff34e955c6c2..beb57d1b2f3a 100644 --- a/Libraries/LibWeb/CSS/Interpolation.cpp +++ b/Libraries/LibWeb/CSS/Interpolation.cpp @@ -112,15 +112,17 @@ static RefPtr interpolate_scale(StyleValue const& a_from, Styl auto const& from_transform = from.as_transformation(); auto const& to_transform = to.as_transformation(); + auto from_values = from_transform.values(); + auto to_values = to_transform.values(); - auto interpolated_x = interpolate_raw(number_from_style_value(from_transform.values()[0], 1), number_from_style_value(to_transform.values()[0], 1), delta, infinite_range); - auto interpolated_y = interpolate_raw(number_from_style_value(from_transform.values()[1], 1), number_from_style_value(to_transform.values()[1], 1), delta, infinite_range); + auto interpolated_x = interpolate_raw(number_from_style_value(from_values[0], 1), number_from_style_value(to_values[0], 1), delta, infinite_range); + auto interpolated_y = interpolate_raw(number_from_style_value(from_values[1], 1), number_from_style_value(to_values[1], 1), delta, infinite_range); Optional interpolated_z; - if (from_transform.values().size() == 3 || to_transform.values().size() == 3) { + if (from_values.size() == 3 || to_values.size() == 3) { static auto const& one_value = NumberStyleValue::create(1).leak_ref(); - auto from = from_transform.values().size() == 3 ? from_transform.values()[2] : ValueComparingNonnullRefPtr { one_value }; - auto to = to_transform.values().size() == 3 ? to_transform.values()[2] : ValueComparingNonnullRefPtr { one_value }; + auto from = from_values.size() == 3 ? from_values[2] : ValueComparingNonnullRefPtr { one_value }; + auto to = to_values.size() == 3 ? to_values[2] : ValueComparingNonnullRefPtr { one_value }; interpolated_z = interpolate_raw(number_from_style_value(from, 1), number_from_style_value(to, 1), delta, infinite_range); } @@ -217,7 +219,7 @@ static RefPtr interpolate_filter_function(DOM::Element& static bool contains_url(StyleValueList const& list) { - return list.values().contains([](auto& it) { return it->is_url(); }); + return any_of(list.values(), [](auto& it) { return it->is_url(); }); } // https://drafts.fxtf.org/filter-effects/#interpolation-of-filters @@ -235,9 +237,11 @@ static RefPtr interpolate_filter_value_list(DOM::Element& elem auto interpolate_filter_values = [&](StyleValueList const& from, StyleValueList const& to) -> RefPtr { StyleValueVector interpolated_filter_values; + auto from_values = from.values(); + auto to_values = to.values(); for (size_t i = 0; i < from.size(); ++i) { - auto const& from_value = from.values()[i]->as_filter(); - auto const& to_value = to.values()[i]->as_filter(); + auto const& from_value = from_values[i]->as_filter(); + auto const& to_value = to_values[i]->as_filter(); auto interpolated_value = interpolate_filter_function(element, calculation_context, from_value, to_value, delta, allow_discrete); if (!interpolated_value) @@ -260,7 +264,7 @@ static RefPtr interpolate_filter_value_list(DOM::Element& elem // 1. Append the missing equivalent s from the longer list to the end of the shorter list. The new added s must be initialized to their initial values for interpolation. auto append_missing_values_to = [&](StyleValueList const& short_list, StyleValueList const& longer_list) -> ValueComparingNonnullRefPtr { - StyleValueVector new_filter_list = short_list.values(); + StyleValueVector new_filter_list { short_list.values() }; for (size_t i = new_filter_list.size(); i < longer_list.size(); ++i) new_filter_list.append(FilterStyleValue::initial_value_for(longer_list.values()[i]->as_filter(), true)); return make_filter_value_list(move(new_filter_list)); @@ -311,19 +315,21 @@ static RefPtr interpolate_translate(DOM::Element& element, Cal auto const& from_transform = from.as_transformation(); auto const& to_transform = to.as_transformation(); + auto from_values = from_transform.values(); + auto to_values = to_transform.values(); - auto interpolated_x = interpolate_value(element, calculation_context, from_transform.values()[0], to_transform.values()[0], delta, allow_discrete); + auto interpolated_x = interpolate_value(element, calculation_context, from_values[0], to_values[0], delta, allow_discrete); if (!interpolated_x) return {}; - auto interpolated_y = interpolate_value(element, calculation_context, from_transform.values()[1], to_transform.values()[1], delta, allow_discrete); + auto interpolated_y = interpolate_value(element, calculation_context, from_values[1], to_values[1], delta, allow_discrete); if (!interpolated_y) return {}; RefPtr interpolated_z; - if (from_transform.values().size() == 3 || to_transform.values().size() == 3) { - auto from_z = from_transform.values().size() == 3 ? from_transform.values()[2] : zero_px; - auto to_z = to_transform.values().size() == 3 ? to_transform.values()[2] : zero_px; + if (from_values.size() == 3 || to_values.size() == 3) { + auto from_z = from_values.size() == 3 ? from_values[2] : zero_px; + auto to_z = to_values.size() == 3 ? to_values[2] : zero_px; interpolated_z = interpolate_value(element, calculation_context, from_z, to_z, delta, allow_discrete); if (!interpolated_z) return {}; @@ -377,31 +383,33 @@ static RefPtr interpolate_rotate(DOM::Element& element, Calcul auto from_transform_type = from_transform.transform_function(); auto to_transform_type = to_transform.transform_function(); + auto from_values = from_transform.values(); + auto to_values = to_transform.values(); - if (from_transform_type == to_transform_type && from_transform.values().size() == 1) { - auto interpolated_angle = interpolate_value(element, calculation_context, from_transform.values()[0], to_transform.values()[0], delta, allow_discrete); + if (from_transform_type == to_transform_type && from_values.size() == 1) { + auto interpolated_angle = interpolate_value(element, calculation_context, from_values[0], to_values[0], delta, allow_discrete); if (!interpolated_angle) return {}; return TransformationStyleValue::create(PropertyID::Rotate, from_transform_type, { *interpolated_angle.release_nonnull() }); } FloatVector3 from_axis { 0, 0, 1 }; - auto from_angle_value = from_transform.values()[0]; - if (from_transform.values().size() == 4) { - from_axis.set_x(from_transform.values()[0]->as_number().number()); - from_axis.set_y(from_transform.values()[1]->as_number().number()); - from_axis.set_z(from_transform.values()[2]->as_number().number()); - from_angle_value = from_transform.values()[3]; + auto from_angle_value = from_values[0]; + if (from_values.size() == 4) { + from_axis.set_x(from_values[0]->as_number().number()); + from_axis.set_y(from_values[1]->as_number().number()); + from_axis.set_z(from_values[2]->as_number().number()); + from_angle_value = from_values[3]; } float from_angle = Angle::from_style_value(from_angle_value, {}).to_radians(); FloatVector3 to_axis { 0, 0, 1 }; - auto to_angle_value = to_transform.values()[0]; - if (to_transform.values().size() == 4) { - to_axis.set_x(to_transform.values()[0]->as_number().number()); - to_axis.set_y(to_transform.values()[1]->as_number().number()); - to_axis.set_z(to_transform.values()[2]->as_number().number()); - to_angle_value = to_transform.values()[3]; + auto to_angle_value = to_values[0]; + if (to_values.size() == 4) { + to_axis.set_x(to_values[0]->as_number().number()); + to_axis.set_y(to_values[1]->as_number().number()); + to_axis.set_z(to_values[2]->as_number().number()); + to_angle_value = to_values[3]; } float to_angle = Angle::from_style_value(to_angle_value, {}).to_radians(); @@ -1089,42 +1097,43 @@ RefPtr interpolate_transform(DOM::Element& element, Calculatio -> NonnullRefPtr { TransformFunction generic_function; StyleValueVector parameters; + auto values = transform->values(); switch (transform->transform_function()) { case TransformFunction::Scale: generic_function = TransformFunction::Scale; - parameters.append(transform->values()[0]); - parameters.append(transform->values().size() > 1 ? transform->values()[1] : transform->values()[0]); + parameters.append(values[0]); + parameters.append(values.size() > 1 ? values[1] : values[0]); break; case TransformFunction::ScaleX: generic_function = TransformFunction::Scale; - parameters.append(transform->values()[0]); + parameters.append(values[0]); parameters.append(NumberStyleValue::create(1.)); break; case TransformFunction::ScaleY: generic_function = TransformFunction::Scale; parameters.append(NumberStyleValue::create(1.)); - parameters.append(transform->values()[0]); + parameters.append(values[0]); break; case TransformFunction::Rotate: generic_function = TransformFunction::Rotate; - parameters.append(transform->values()[0]); + parameters.append(values[0]); break; case TransformFunction::Translate: generic_function = TransformFunction::Translate; - parameters.append(transform->values()[0]); - parameters.append(transform->values().size() > 1 - ? transform->values()[1] + parameters.append(values[0]); + parameters.append(values.size() > 1 + ? values[1] : LengthStyleValue::create(Length::make_px(0.))); break; case TransformFunction::TranslateX: generic_function = TransformFunction::Translate; - parameters.append(transform->values()[0]); + parameters.append(values[0]); parameters.append(LengthStyleValue::create(Length::make_px(0.))); break; case TransformFunction::TranslateY: generic_function = TransformFunction::Translate; parameters.append(LengthStyleValue::create(Length::make_px(0.))); - parameters.append(transform->values()[0]); + parameters.append(values[0]); break; default: VERIFY_NOT_REACHED(); @@ -1140,6 +1149,7 @@ RefPtr interpolate_transform(DOM::Element& element, Calculatio TransformFunction generic_function; StyleValueVector parameters; + auto values = transform->values(); switch (transform->transform_function()) { case TransformFunction::Rotate: case TransformFunction::RotateZ: @@ -1147,39 +1157,39 @@ RefPtr interpolate_transform(DOM::Element& element, Calculatio parameters.append(NumberStyleValue::create(0.)); parameters.append(NumberStyleValue::create(0.)); parameters.append(NumberStyleValue::create(1.)); - parameters.append(transform->values()[0]); + parameters.append(values[0]); break; case TransformFunction::RotateX: generic_function = TransformFunction::Rotate3d; parameters.append(NumberStyleValue::create(1.)); parameters.append(NumberStyleValue::create(0.)); parameters.append(NumberStyleValue::create(0.)); - parameters.append(transform->values()[0]); + parameters.append(values[0]); break; case TransformFunction::RotateY: generic_function = TransformFunction::Rotate3d; parameters.append(NumberStyleValue::create(0.)); parameters.append(NumberStyleValue::create(1.)); parameters.append(NumberStyleValue::create(0.)); - parameters.append(transform->values()[0]); + parameters.append(values[0]); break; case TransformFunction::Scale: generic_function = TransformFunction::Scale3d; - parameters.append(transform->values()[0]); - parameters.append(transform->values().size() > 1 ? transform->values()[1] : transform->values()[0]); + parameters.append(values[0]); + parameters.append(values.size() > 1 ? values[1] : values[0]); parameters.append(NumberStyleValue::create(1.)); break; case TransformFunction::ScaleZ: generic_function = TransformFunction::Scale3d; parameters.append(NumberStyleValue::create(1.)); parameters.append(NumberStyleValue::create(1.)); - parameters.append(transform->values()[0]); + parameters.append(values[0]); break; case TransformFunction::Translate: generic_function = TransformFunction::Translate3d; - parameters.append(transform->values()[0]); - parameters.append(transform->values().size() > 1 - ? transform->values()[1] + parameters.append(values[0]); + parameters.append(values.size() > 1 + ? values[1] : LengthStyleValue::create(Length::make_px(0.))); parameters.append(LengthStyleValue::create(Length::make_px(0.))); break; @@ -1187,7 +1197,7 @@ RefPtr interpolate_transform(DOM::Element& element, Calculatio generic_function = TransformFunction::Translate3d; parameters.append(LengthStyleValue::create(Length::make_px(0.))); parameters.append(LengthStyleValue::create(Length::make_px(0.))); - parameters.append(transform->values()[0]); + parameters.append(values[0]); break; default: generic_function = TransformFunction::Matrix3d; @@ -1252,8 +1262,8 @@ RefPtr interpolate_transform(DOM::Element& element, Calculatio // NB: We converted both functions to their primitives. But if they're different primitives or if they have a // different number of values, we can't interpolate numerically between them. Break here so the next loop // can take care of the remaining functions. - auto const& from_values = from_transformation->values(); - auto const& to_values = to_transformation->values(); + auto from_values = from_transformation->values(); + auto to_values = to_transformation->values(); if (from_function != to_function || from_values.size() != to_values.size()) break; @@ -1341,7 +1351,7 @@ RefPtr interpolate_box_shadow(DOM::Element& element, Calculati if (value.to_keyword() == Keyword::None) return {}; - return value.as_value_list().values(); + return StyleValueVector { value.as_value_list().values() }; }; static constexpr auto extend_list_if_necessary = [](StyleValueVector& values, StyleValueVector const& other) { @@ -2566,8 +2576,8 @@ RefPtr composite_value(PropertyID property_id, StyleValue cons // Given two filter values representing an base value (base filter list) and a value to add (added filter list), // returns the concatenation of the the two lists: ‘base filter list added filter list’. if (composite_operation == Bindings::CompositeOperation::Add) { - StyleValueVector result = underlying_list.values(); - result.extend(animated_list.values()); + StyleValueVector result { underlying_list.values() }; + result.extend(StyleValueVector { animated_list.values() }); return StyleValueList::create(move(result), StyleValueList::Separator::Space, StyleValueList::Collapsible::No); } diff --git a/Libraries/LibWeb/CSS/ParsedFontFace.cpp b/Libraries/LibWeb/CSS/ParsedFontFace.cpp index 52c305518cc7..bda98211f3e7 100644 --- a/Libraries/LibWeb/CSS/ParsedFontFace.cpp +++ b/Libraries/LibWeb/CSS/ParsedFontFace.cpp @@ -82,7 +82,7 @@ ParsedFontFace ParsedFontFace::from_descriptors(CSSFontFaceDescriptors const& de weight = { 400, 400 }; } else { auto absolutized = value->absolutized(computation_context); - auto& weight_values = absolutized->as_value_list().values(); + auto weight_values = absolutized->as_value_list().values(); if (weight_values.size() == 1) { auto one_weight = static_cast(StyleComputer::compute_font_weight(weight_values[0], {})->as_number().number()); weight = { one_weight, one_weight }; diff --git a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp index 05b77f679518..0be36a050c0e 100644 --- a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp @@ -4515,7 +4515,7 @@ RefPtr Parser::parse_transition_value(TokenStream, then the declaration is invalid. auto const& transition_properties = parsed_value->as_shorthand().longhand(PropertyID::TransitionProperty)->as_value_list().values(); - if (transition_properties.size() > 1 && transition_properties.contains([](auto const& transition_property) { return transition_property->to_keyword() == Keyword::None; })) + if (transition_properties.size() > 1 && any_of(transition_properties, [](auto const& transition_property) { return transition_property->to_keyword() == Keyword::None; })) return nullptr; return parsed_value; @@ -5090,7 +5090,7 @@ RefPtr Parser::parse_grid_shorthand_value(TokenStreamas_grid_track_size_list().grid_track_size_list().is_empty()) + if (grid_auto_rows->as_grid_track_size_list().is_empty()) grid_auto_rows = property_initial_value(PropertyID::GridAutoRows); tokens.discard_whitespace(); @@ -5129,7 +5129,7 @@ RefPtr Parser::parse_grid_shorthand_value(TokenStreamas_grid_track_size_list().grid_track_size_list().is_empty()) + if (grid_auto_columns->as_grid_track_size_list().is_empty()) grid_auto_columns = property_initial_value(PropertyID::GridAutoColumns); transaction.commit(); diff --git a/Libraries/LibWeb/CSS/Serialize.cpp b/Libraries/LibWeb/CSS/Serialize.cpp index 98595dbb3f36..168255fc5115 100644 --- a/Libraries/LibWeb/CSS/Serialize.cpp +++ b/Libraries/LibWeb/CSS/Serialize.cpp @@ -501,7 +501,7 @@ String serialize_a_series_of_component_values_preserving_original_source_text(Re return builder.to_string_without_validation(); } -String serialize_a_positional_value_list(StyleValueVector const& values, SerializationMode mode) +String serialize_a_positional_value_list(ReadonlySpan> values, SerializationMode mode) { switch (values.size()) { case 2: { diff --git a/Libraries/LibWeb/CSS/Serialize.h b/Libraries/LibWeb/CSS/Serialize.h index edb9e24995e4..2b6cb75ff9dd 100644 --- a/Libraries/LibWeb/CSS/Serialize.h +++ b/Libraries/LibWeb/CSS/Serialize.h @@ -59,6 +59,6 @@ Utf16String serialize_a_css_declaration_to_utf16(Utf16View property, Utf16View v Utf16String serialize_a_series_of_component_values(ReadonlySpan); String serialize_a_series_of_component_values_preserving_original_source_text(ReadonlySpan); -String serialize_a_positional_value_list(StyleValueVector const& values, SerializationMode mode); +String serialize_a_positional_value_list(ReadonlySpan> values, SerializationMode mode); } diff --git a/Libraries/LibWeb/CSS/StyleComputer.cpp b/Libraries/LibWeb/CSS/StyleComputer.cpp index 4f3c32fbb744..5810fc178b47 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -863,8 +863,8 @@ void StyleComputer::for_each_property_expanding_shorthands(PropertyID property_i if (value.is_shorthand()) { auto& shorthand_value = value.as_shorthand(); - auto& properties = shorthand_value.sub_properties(); - auto& values = shorthand_value.values(); + auto properties = shorthand_value.sub_properties(); + auto values = shorthand_value.values(); for (size_t i = 0; i < properties.size(); ++i) for_each_property_expanding_shorthands(properties[i], values[i], set_longhand_property); return; @@ -4189,9 +4189,10 @@ NonnullRefPtr StyleComputer::compute_font_feature_tag_value_li return absolutized_value; auto const& value_list = absolutized_value->as_value_list(); + auto values = value_list.values(); OrderedHashMap> axis_tags_map; - for (size_t i = 0; i < value_list.values().size(); i++) { - auto const& axis_tag = value_list.values().at(i)->as_open_type_tagged(); + for (size_t i = 0; i < values.size(); i++) { + auto const& axis_tag = values.at(i)->as_open_type_tagged(); axis_tags_map.set(axis_tag.tag(), axis_tag); } @@ -4533,8 +4534,9 @@ NonnullRefPtr StyleComputer::compute_position_area(NonnullRefP auto const& value_list = absolutized_value->as_value_list(); VERIFY(value_list.size() == 2); - auto const& block_value = value_list.values().at(0); - auto const& inline_value = value_list.values().at(1); + auto values = value_list.values(); + auto const& block_value = values.at(0); + auto const& inline_value = values.at(1); if (block_value->as_keyword().keyword() == Keyword::SpanAll) { switch (inline_value->as_keyword().keyword()) { case Keyword::Start: diff --git a/Libraries/LibWeb/CSS/StylePropertyMap.cpp b/Libraries/LibWeb/CSS/StylePropertyMap.cpp index 5aea413381e1..58bd96e1085b 100644 --- a/Libraries/LibWeb/CSS/StylePropertyMap.cpp +++ b/Libraries/LibWeb/CSS/StylePropertyMap.cpp @@ -282,7 +282,7 @@ WebIDL::ExceptionOr StylePropertyMap::append(Utf16FlyString property_name, StyleValueVector value_list; if (existing_value) { if (existing_value->is_value_list()) - value_list.extend(existing_value->as_value_list().values()); + value_list.extend(StyleValueVector { existing_value->as_value_list().values() }); else value_list.append(existing_value.release_nonnull()); } diff --git a/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.cpp index a32c2adac901..b235cb4b8205 100644 --- a/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.cpp @@ -10,6 +10,42 @@ namespace Web::CSS { +StyleValueFFI::RetainedColorStop retain_color_stop_for_rust(ColorStopListElement const& stop) +{ + return { { retain_style_value_for_rust(stop.transition_hint.ptr()) }, { retain_style_value_for_rust(stop.color_stop.color.ptr()) }, + { retain_style_value_for_rust(stop.color_stop.position.ptr()) }, { retain_style_value_for_rust(stop.color_stop.second_position.ptr()) } }; +} + +Vector retain_color_stops_for_rust(ReadonlySpan color_stop_list) +{ + Vector stops; + stops.ensure_capacity(color_stop_list.size()); + for (auto const& stop : color_stop_list) + stops.unchecked_append(retain_color_stop_for_rust(stop)); + return stops; +} + +ColorStopListElement color_stop_from_rust_data(StyleValueFFI::RetainedColorStop const& stop) +{ + return { + .transition_hint = static_cast(stop.transition_hint.pointer), + .color_stop = { + .color = static_cast(stop.color.pointer), + .position = static_cast(stop.position.pointer), + .second_position = static_cast(stop.second_position.pointer), + }, + }; +} + +Vector color_stops_from_rust_data(StyleValueFFI::RetainedColorStop const* color_stop_list, size_t size) +{ + Vector stops; + stops.ensure_capacity(size); + for (size_t i = 0; i < size; ++i) + stops.unchecked_append(color_stop_from_rust_data(color_stop_list[i])); + return stops; +} + // https://drafts.css-houdini.org/css-typed-om-1/#reify-stylevalue GC::Ref AbstractImageStyleValue::reify(JS::Realm& realm, Utf16FlyString const&) const { @@ -40,7 +76,7 @@ ColorStopListElement ColorStopListElement::absolutized(ComputationContext const& }; } -void serialize_color_stop_list(StringBuilder& builder, Vector const& color_stop_list, SerializationMode mode) +void serialize_color_stop_list(StringBuilder& builder, ReadonlySpan color_stop_list, SerializationMode mode) { bool first = true; for (auto const& element : color_stop_list) { diff --git a/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h index 355d1d229f89..3778633e68ae 100644 --- a/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h @@ -12,10 +12,11 @@ #include #include #include +#include namespace Web::CSS { -class AbstractImageStyleValue : public StyleValue { +class WEB_API AbstractImageStyleValue : public StyleValue { public: using StyleValue::StyleValue; @@ -40,7 +41,7 @@ class AbstractImageStyleValue : public StyleValue { virtual Optional color_if_single_pixel_bitmap(DOM::Document const&) const { return {}; } - virtual GC::Ref reify(JS::Realm&, Utf16FlyString const& associated_property) const override; + GC::Ref reify(JS::Realm&, Utf16FlyString const& associated_property) const; }; // And now, some gradient related things. Maybe these should live somewhere else. @@ -69,6 +70,19 @@ struct ColorStopListElement { && (!color_stop.second_position || color_stop.second_position->is_computationally_independent()); } }; -void serialize_color_stop_list(StringBuilder&, Vector const&, SerializationMode); +void serialize_color_stop_list(StringBuilder&, ReadonlySpan, SerializationMode); + +namespace StyleValueFFI { + +struct RetainedColorStop; + +} + +// Marshals a color stop for a Rust-owned gradient allocation, retaining one strong reference +// to each non-null sub-value. +StyleValueFFI::RetainedColorStop retain_color_stop_for_rust(ColorStopListElement const&); +Vector retain_color_stops_for_rust(ReadonlySpan); +ColorStopListElement color_stop_from_rust_data(StyleValueFFI::RetainedColorStop const&); +Vector color_stops_from_rust_data(StyleValueFFI::RetainedColorStop const*, size_t); } diff --git a/Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.cpp index e4485a882a44..38bb2e2e776a 100644 --- a/Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.cpp @@ -10,6 +10,19 @@ namespace Web::CSS { +static StyleValueFFI::StyleValueData* make_anchor_size_data(Optional const& anchor_name, Optional const& anchor_size, ValueComparingRefPtr const& fallback_value) +{ + // The Rust allocation takes ownership of one strong reference to the fallback value. + if (fallback_value) + fallback_value->ref(); + return StyleValueFFI::rust_style_value_create_anchor_size( + anchor_name.has_value(), + anchor_name.has_value() ? anchor_name->to_raw_leaked() : 0, + anchor_size.has_value(), + anchor_size.has_value() ? to_underlying(*anchor_size) : 0, + fallback_value.ptr()); +} + ValueComparingNonnullRefPtr AnchorSizeStyleValue::create( Optional const& anchor_name, Optional const& anchor_size, ValueComparingRefPtr const& fallback_value) @@ -21,8 +34,7 @@ AnchorSizeStyleValue::AnchorSizeStyleValue( Optional const& anchor_name, Optional const& anchor_size, ValueComparingRefPtr const& fallback_value) - : StyleValueWithDefaultOperators(Type::AnchorSize) - , m_properties { .anchor_name = anchor_name, .anchor_size = anchor_size, .fallback_value = fallback_value } + : StyleValueWithDefaultOperators(Type::AnchorSize, make_anchor_size_data(anchor_name, anchor_size, fallback_value)) { } diff --git a/Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h index c3ed7d128fe4..0cf89bfa74d6 100644 --- a/Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h @@ -20,17 +20,27 @@ class AnchorSizeStyleValue final : public StyleValueWithDefaultOperators const& fallback_value); virtual ~AnchorSizeStyleValue() override = default; - virtual void serialize(StringBuilder&, SerializationMode) const override; + void serialize(StringBuilder&, SerializationMode) const; - bool properties_equal(AnchorSizeStyleValue const& other) const { return m_properties == other.m_properties; } + bool properties_equal(AnchorSizeStyleValue const& other) const { return anchor_name() == other.anchor_name() && anchor_size() == other.anchor_size() && fallback_value() == other.fallback_value(); } - virtual bool is_computationally_independent() const override { return true; } + bool is_computationally_independent() const { return true; } - Optional anchor_name() const { return m_properties.anchor_name; } - Optional anchor_size() const { return m_properties.anchor_size; } + Optional anchor_name() const + { + if (!m_value->anchor_size.has_anchor_name) + return {}; + return Utf16FlyString::from_raw(m_value->anchor_size.anchor_name.raw); + } + Optional anchor_size() const + { + if (!m_value->anchor_size.has_anchor_size) + return {}; + return static_cast(m_value->anchor_size.anchor_size); + } ValueComparingRefPtr fallback_value() const { - return m_properties.fallback_value; + return static_cast(m_value->anchor_size.fallback_value.pointer); } private: @@ -38,13 +48,6 @@ class AnchorSizeStyleValue final : public StyleValueWithDefaultOperators const& anchor_name, Optional const& anchor_size, ValueComparingRefPtr const& fallback_value); - - struct Properties { - Optional anchor_name; - Optional anchor_size; - ValueComparingRefPtr fallback_value; - bool operator==(Properties const&) const = default; - } m_properties; }; } diff --git a/Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.cpp index 1b13d72a327e..c43e4f0b4300 100644 --- a/Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.cpp @@ -11,6 +11,20 @@ namespace Web::CSS { +static StyleValueFFI::StyleValueData* make_anchor_data(Optional const& anchor_name, ValueComparingNonnullRefPtr const& anchor_side, ValueComparingRefPtr const& fallback_value) +{ + // The Rust allocation takes ownership of one strong reference to the side and, when present, + // the fallback value. + anchor_side->ref(); + if (fallback_value) + fallback_value->ref(); + return StyleValueFFI::rust_style_value_create_anchor( + anchor_name.has_value(), + anchor_name.has_value() ? anchor_name->to_raw_leaked() : 0, + anchor_side.ptr(), + fallback_value.ptr()); +} + ValueComparingNonnullRefPtr AnchorStyleValue::create( Optional const& anchor_name, ValueComparingNonnullRefPtr const& anchor_side, @@ -22,8 +36,7 @@ ValueComparingNonnullRefPtr AnchorStyleValue::create( AnchorStyleValue::AnchorStyleValue(Optional const& anchor_name, ValueComparingNonnullRefPtr const& anchor_side, ValueComparingRefPtr const& fallback_value) - : AbstractNonMathCalcFunctionStyleValue(Type::Anchor) - , m_properties { .anchor_name = anchor_name, .anchor_side = anchor_side, .fallback_value = fallback_value } + : AbstractNonMathCalcFunctionStyleValue(Type::Anchor, make_anchor_data(anchor_name, anchor_side, fallback_value)) { } @@ -61,7 +74,7 @@ RefPtr AnchorStyleValue::resolve_to_calculation_node(Calc // If any of these conditions are false, the anchor() function computes to its specified fallback value. If no // fallback value is specified, it makes the declaration referencing it invalid at computed-value time. - auto const& fallback_value = m_properties.fallback_value; + auto fallback_value = this->fallback_value(); if (!fallback_value) return nullptr; @@ -77,7 +90,8 @@ bool AnchorStyleValue::equals(StyleValue const& other) const if (type() != other.type()) return false; - return m_properties == other.as_anchor().m_properties; + auto const& other_anchor = other.as_anchor(); + return anchor_name() == other_anchor.anchor_name() && anchor_side() == other_anchor.anchor_side() && fallback_value() == other_anchor.fallback_value(); } } diff --git a/Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.h index adbc4d413af6..e2d94dd12129 100644 --- a/Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.h @@ -20,32 +20,30 @@ class AnchorStyleValue final : public AbstractNonMathCalcFunctionStyleValue { ValueComparingRefPtr const& fallback_value); virtual ~AnchorStyleValue() override = default; - virtual void serialize(StringBuilder&, SerializationMode) const override; + void serialize(StringBuilder&, SerializationMode) const; virtual RefPtr resolve_to_calculation_node(CalculationContext const&, CalculationResolutionContext const&) const override; - virtual bool equals(StyleValue const& other) const override; + bool equals(StyleValue const& other) const; - virtual bool is_computationally_independent() const override { return true; } + bool is_computationally_independent() const { return true; } - Optional anchor_name() const { return m_properties.anchor_name; } + Optional anchor_name() const + { + if (!m_value->anchor.has_anchor_name) + return {}; + return Utf16FlyString::from_raw(m_value->anchor.anchor_name.raw); + } ValueComparingNonnullRefPtr anchor_side() const { - return m_properties.anchor_side; + return *static_cast(m_value->anchor.anchor_side.pointer); } ValueComparingRefPtr fallback_value() const { - return m_properties.fallback_value; + return static_cast(m_value->anchor.fallback_value.pointer); } private: AnchorStyleValue(Optional const& anchor_name, ValueComparingNonnullRefPtr const& anchor_side, ValueComparingRefPtr const& fallback_value); - - struct Properties { - Optional anchor_name; - ValueComparingNonnullRefPtr anchor_side; - ValueComparingRefPtr fallback_value; - bool operator==(Properties const&) const = default; - } m_properties; }; } diff --git a/Libraries/LibWeb/CSS/StyleValues/AngleStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/AngleStyleValue.cpp index e99fc448ade1..b0847f04a96c 100644 --- a/Libraries/LibWeb/CSS/StyleValues/AngleStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/AngleStyleValue.cpp @@ -12,8 +12,7 @@ namespace Web::CSS { AngleStyleValue::AngleStyleValue(Angle angle) - : DimensionStyleValue(Type::Angle) - , m_angle(move(angle)) + : DimensionStyleValue(Type::Angle, StyleValueFFI::rust_style_value_create_angle(angle.raw_value(), to_underlying(angle.unit()))) { } @@ -21,14 +20,14 @@ AngleStyleValue::~AngleStyleValue() = default; ValueComparingNonnullRefPtr AngleStyleValue::absolutized(ComputationContext const&) const { - if (m_angle.unit() == canonical_angle_unit()) + if (angle().unit() == canonical_angle_unit()) return *this; - return create(Angle::make_degrees(m_angle.to_degrees())); + return create(Angle::make_degrees(angle().to_degrees())); } void AngleStyleValue::serialize(StringBuilder& builder, SerializationMode mode) const { - m_angle.serialize(builder, mode); + angle().serialize(builder, mode); } bool AngleStyleValue::equals(StyleValue const& other) const @@ -36,7 +35,7 @@ bool AngleStyleValue::equals(StyleValue const& other) const if (type() != other.type()) return false; auto const& other_angle = other.as_angle(); - return m_angle == other_angle.m_angle; + return angle() == other_angle.angle(); } } diff --git a/Libraries/LibWeb/CSS/StyleValues/AngleStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/AngleStyleValue.h index b56322a6dd54..438bdf8558ef 100644 --- a/Libraries/LibWeb/CSS/StyleValues/AngleStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/AngleStyleValue.h @@ -22,22 +22,20 @@ class AngleStyleValue : public DimensionStyleValue { } virtual ~AngleStyleValue() override; - Angle const& angle() const { return m_angle; } - virtual double raw_value() const override { return m_angle.raw_value(); } - virtual Utf16FlyString unit_name() const override { return m_angle.unit_name(); } + Angle angle() const { return Angle(m_value->angle.value, static_cast(m_value->angle.unit)); } + virtual double raw_value() const override { return m_value->angle.value; } + virtual Utf16FlyString unit_name() const override { return angle().unit_name(); } - virtual ValueComparingNonnullRefPtr absolutized(ComputationContext const&) const override; + ValueComparingNonnullRefPtr absolutized(ComputationContext const&) const; - virtual void serialize(StringBuilder&, SerializationMode) const override; + void serialize(StringBuilder&, SerializationMode) const; - bool equals(StyleValue const& other) const override; + bool equals(StyleValue const& other) const; - virtual bool is_computationally_independent() const override { return true; } + bool is_computationally_independent() const { return true; } private: explicit AngleStyleValue(Angle angle); - - Angle m_angle; }; } diff --git a/Libraries/LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.cpp index 93519f75781c..c9842fadab64 100644 --- a/Libraries/LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.cpp @@ -12,8 +12,7 @@ namespace Web::CSS { BackgroundSizeStyleValue::BackgroundSizeStyleValue(ValueComparingNonnullRefPtr size_x, ValueComparingNonnullRefPtr size_y) - : StyleValueWithDefaultOperators(Type::BackgroundSize) - , m_properties { .size_x = move(size_x), .size_y = move(size_y) } + : StyleValueWithDefaultOperators(Type::BackgroundSize, StyleValueFFI::rust_style_value_create_background_size(&size_x.leak_ref(), &size_y.leak_ref())) { } @@ -21,21 +20,21 @@ BackgroundSizeStyleValue::~BackgroundSizeStyleValue() = default; void BackgroundSizeStyleValue::serialize(StringBuilder& builder, SerializationMode mode) const { - if (m_properties.size_x->has_auto() && m_properties.size_y->has_auto()) { + if (size_x()->has_auto() && size_y()->has_auto()) { builder.append("auto"sv); return; } - m_properties.size_x->serialize(builder, mode); + size_x()->serialize(builder, mode); builder.append(' '); - m_properties.size_y->serialize(builder, mode); + size_y()->serialize(builder, mode); } ValueComparingNonnullRefPtr BackgroundSizeStyleValue::absolutized(ComputationContext const& computation_context) const { - auto absolutized_size_x = m_properties.size_x->absolutized(computation_context); - auto absolutized_size_y = m_properties.size_y->absolutized(computation_context); + auto absolutized_size_x = size_x()->absolutized(computation_context); + auto absolutized_size_y = size_y()->absolutized(computation_context); - if (absolutized_size_x == m_properties.size_x && absolutized_size_y == m_properties.size_y) + if (absolutized_size_x == size_x() && absolutized_size_y == size_y()) return *this; return BackgroundSizeStyleValue::create(absolutized_size_x, absolutized_size_y); diff --git a/Libraries/LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h index 85603b84971a..db992f8a54bd 100644 --- a/Libraries/LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h @@ -24,24 +24,18 @@ class BackgroundSizeStyleValue final : public StyleValueWithDefaultOperators size_x() const { return m_properties.size_x; } - ValueComparingNonnullRefPtr size_y() const { return m_properties.size_y; } + ValueComparingNonnullRefPtr size_x() const { return *static_cast(m_value->background_size.size_x.pointer); } + ValueComparingNonnullRefPtr size_y() const { return *static_cast(m_value->background_size.size_y.pointer); } - virtual void serialize(StringBuilder&, SerializationMode) const override; - virtual ValueComparingNonnullRefPtr absolutized(ComputationContext const&) const override; + void serialize(StringBuilder&, SerializationMode) const; + ValueComparingNonnullRefPtr absolutized(ComputationContext const&) const; - bool properties_equal(BackgroundSizeStyleValue const& other) const { return m_properties == other.m_properties; } + bool properties_equal(BackgroundSizeStyleValue const& other) const { return size_x() == other.size_x() && size_y() == other.size_y(); } - virtual bool is_computationally_independent() const override { return m_properties.size_x->is_computationally_independent() && m_properties.size_y->is_computationally_independent(); } + bool is_computationally_independent() const { return size_x()->is_computationally_independent() && size_y()->is_computationally_independent(); } private: BackgroundSizeStyleValue(ValueComparingNonnullRefPtr size_x, ValueComparingNonnullRefPtr size_y); - - struct Properties { - ValueComparingNonnullRefPtr size_x; - ValueComparingNonnullRefPtr size_y; - bool operator==(Properties const&) const = default; - } m_properties; }; } diff --git a/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.cpp index a548460885b9..750e86c891f2 100644 --- a/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.cpp @@ -14,10 +14,47 @@ #include #include #include +#include #include namespace Web::CSS { +StyleValueFFI::StyleValueData* BasicShapeStyleValue::make_basic_shape_data(BasicShape const& basic_shape) +{ + // The Rust allocation takes ownership of one strong reference to each non-null value. + return basic_shape.visit( + [](Inset const& inset) { + return StyleValueFFI::rust_style_value_create_basic_shape(0, retain_style_value_for_rust(inset.top.ptr()), retain_style_value_for_rust(inset.right.ptr()), retain_style_value_for_rust(inset.bottom.ptr()), retain_style_value_for_rust(inset.left.ptr()), retain_style_value_for_rust(inset.border_radius.ptr()), 0, nullptr, 0, 0); + }, + [](Xywh const& xywh) { + return StyleValueFFI::rust_style_value_create_basic_shape(1, retain_style_value_for_rust(xywh.x.ptr()), retain_style_value_for_rust(xywh.y.ptr()), retain_style_value_for_rust(xywh.width.ptr()), retain_style_value_for_rust(xywh.height.ptr()), retain_style_value_for_rust(xywh.border_radius.ptr()), 0, nullptr, 0, 0); + }, + [](Rect const& rect) { + return StyleValueFFI::rust_style_value_create_basic_shape(2, retain_style_value_for_rust(rect.top.ptr()), retain_style_value_for_rust(rect.right.ptr()), retain_style_value_for_rust(rect.bottom.ptr()), retain_style_value_for_rust(rect.left.ptr()), retain_style_value_for_rust(rect.border_radius.ptr()), 0, nullptr, 0, 0); + }, + [](Circle const& circle) { + return StyleValueFFI::rust_style_value_create_basic_shape(3, retain_style_value_for_rust(circle.radius.ptr()), retain_style_value_for_rust(circle.position.ptr()), nullptr, nullptr, nullptr, 0, nullptr, 0, 0); + }, + [](Ellipse const& ellipse) { + return StyleValueFFI::rust_style_value_create_basic_shape(4, retain_style_value_for_rust(ellipse.radius.ptr()), retain_style_value_for_rust(ellipse.position.ptr()), nullptr, nullptr, nullptr, 0, nullptr, 0, 0); + }, + [](Polygon const& polygon) { + Vector points; + points.ensure_capacity(polygon.points.size()); + for (auto const& point : polygon.points) + points.unchecked_append({ { retain_style_value_for_rust(point.x.ptr()) }, { retain_style_value_for_rust(point.y.ptr()) } }); + return StyleValueFFI::rust_style_value_create_basic_shape(5, nullptr, nullptr, nullptr, nullptr, nullptr, static_cast(to_underlying(polygon.fill_rule)), points.data(), points.size(), 0); + }, + [](Path const& path) { + return StyleValueFFI::rust_style_value_create_basic_shape(6, nullptr, nullptr, nullptr, nullptr, nullptr, static_cast(to_underlying(path.fill_rule)), nullptr, 0, Utf16String::from_utf8(path.path_instructions.serialize()).to_raw_leaked()); + }); +} + +BasicShape const& BasicShapeStyleValue::basic_shape() const +{ + return m_shape; +} + static Gfx::Path path_from_resolved_rect(float top, float right, float bottom, float left) { Gfx::Path path; @@ -127,7 +164,7 @@ Gfx::Path Inset::to_path(CSSPixelRect reference_box) const void Inset::serialize(StringBuilder& builder, SerializationMode mode) const { builder.append("inset("sv); - builder.append(serialize_a_positional_value_list({ top, right, bottom, left }, mode)); + builder.append(serialize_a_positional_value_list(StyleValueVector { top, right, bottom, left }, mode)); auto serialized_border_radius = border_radius->to_string(mode); @@ -329,7 +366,7 @@ BasicShapeStyleValue::~BasicShapeStyleValue() = default; Gfx::Path BasicShapeStyleValue::to_path(CSSPixelRect reference_box) const { - return m_basic_shape.visit([&](auto const& shape) -> Gfx::Path { + return basic_shape().visit([&](auto const& shape) -> Gfx::Path { // NB: Xywh and Rect don't require to_path functions as we should have already converted them to their // respective Inset equivalents during absolutization if constexpr (requires { shape.to_path(reference_box); }) { @@ -342,7 +379,7 @@ Gfx::Path BasicShapeStyleValue::to_path(CSSPixelRect reference_box) const void BasicShapeStyleValue::serialize(StringBuilder& builder, SerializationMode mode) const { - m_basic_shape.visit([&](auto const& shape) { + basic_shape().visit([&](auto const& shape) { shape.serialize(builder, mode); }); } @@ -373,7 +410,7 @@ ValueComparingNonnullRefPtr BasicShapeStyleValue::absolutized( return value->absolutized(computation_context); }; - auto absolutized_shape = m_basic_shape.visit( + auto absolutized_shape = basic_shape().visit( [&](Inset const& shape) -> BasicShape { auto absolutized_top = shape.top->absolutized(computation_context); auto absolutized_right = shape.right->absolutized(computation_context); @@ -466,7 +503,7 @@ ValueComparingNonnullRefPtr BasicShapeStyleValue::absolutized( return shape; }); - if (absolutized_shape == m_basic_shape) + if (absolutized_shape == basic_shape()) return *this; return BasicShapeStyleValue::create(absolutized_shape); diff --git a/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.h index 0b235d90957f..793426bd53d5 100644 --- a/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.h @@ -159,28 +159,33 @@ class BasicShapeStyleValue : public StyleValueWithDefaultOperators absolutized(ComputationContext const&) const override; + void serialize(StringBuilder&, SerializationMode) const; + ValueComparingNonnullRefPtr absolutized(ComputationContext const&) const; - bool properties_equal(BasicShapeStyleValue const& other) const { return m_basic_shape == other.m_basic_shape; } + bool properties_equal(BasicShapeStyleValue const& other) const { return basic_shape() == other.basic_shape(); } - virtual bool is_computationally_independent() const override + bool is_computationally_independent() const { - return m_basic_shape.visit([](auto const& shape) { return shape.is_computationally_independent(); }); + return basic_shape().visit([](auto const& shape) { return shape.is_computationally_independent(); }); } Gfx::Path to_path(CSSPixelRect reference_box) const; private: BasicShapeStyleValue(BasicShape basic_shape) - : StyleValueWithDefaultOperators(Type::BasicShape) - , m_basic_shape(move(basic_shape)) + : StyleValueWithDefaultOperators(Type::BasicShape, make_basic_shape_data(basic_shape)) + , m_shape(move(basic_shape)) { } - BasicShape m_basic_shape; + static StyleValueFFI::StyleValueData* make_basic_shape_data(BasicShape const&); + + // NB: Eagerly materialized copy of the Rust-owned data (rebuilding a path shape would + // re-parse its serialized path data); the Rust allocation stays authoritative, and the + // copy is immutable after construction, so sharing across style workers is safe. + BasicShape m_shape; }; } diff --git a/Libraries/LibWeb/CSS/StyleValues/BorderImageSliceStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/BorderImageSliceStyleValue.h index 758b4d71fee7..ec74cc668e48 100644 --- a/Libraries/LibWeb/CSS/StyleValues/BorderImageSliceStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/BorderImageSliceStyleValue.h @@ -19,40 +19,30 @@ class BorderImageSliceStyleValue final : public StyleValueWithDefaultOperators top() const { return m_properties.top; } - ValueComparingNonnullRefPtr left() const { return m_properties.left; } - ValueComparingNonnullRefPtr bottom() const { return m_properties.bottom; } - ValueComparingNonnullRefPtr right() const { return m_properties.right; } + ValueComparingNonnullRefPtr top() const { return *static_cast(m_value->border_image_slice.top.pointer); } + ValueComparingNonnullRefPtr left() const { return *static_cast(m_value->border_image_slice.left.pointer); } + ValueComparingNonnullRefPtr bottom() const { return *static_cast(m_value->border_image_slice.bottom.pointer); } + ValueComparingNonnullRefPtr right() const { return *static_cast(m_value->border_image_slice.right.pointer); } - bool fill() const { return m_properties.fill; } + bool fill() const { return m_value->border_image_slice.fill; } - virtual void serialize(StringBuilder&, SerializationMode) const override; + void serialize(StringBuilder&, SerializationMode) const; - bool properties_equal(BorderImageSliceStyleValue const& other) const { return m_properties == other.m_properties; } + bool properties_equal(BorderImageSliceStyleValue const& other) const { return top() == other.top() && right() == other.right() && bottom() == other.bottom() && left() == other.left() && fill() == other.fill(); } - virtual bool is_computationally_independent() const override + bool is_computationally_independent() const { - return m_properties.top->is_computationally_independent() - && m_properties.right->is_computationally_independent() - && m_properties.bottom->is_computationally_independent() - && m_properties.left->is_computationally_independent(); + return top()->is_computationally_independent() + && right()->is_computationally_independent() + && bottom()->is_computationally_independent() + && left()->is_computationally_independent(); } private: BorderImageSliceStyleValue(ValueComparingNonnullRefPtr top, ValueComparingNonnullRefPtr right, ValueComparingNonnullRefPtr bottom, ValueComparingNonnullRefPtr left, bool fill) - : StyleValueWithDefaultOperators(Type::BorderImageSlice) - , m_properties { .top = move(top), .right = move(right), .bottom = move(bottom), .left = move(left), .fill = fill } + : StyleValueWithDefaultOperators(Type::BorderImageSlice, StyleValueFFI::rust_style_value_create_border_image_slice(&top.leak_ref(), &right.leak_ref(), &bottom.leak_ref(), &left.leak_ref(), fill)) { } - - struct Properties { - ValueComparingNonnullRefPtr top; - ValueComparingNonnullRefPtr right; - ValueComparingNonnullRefPtr bottom; - ValueComparingNonnullRefPtr left; - bool fill; - bool operator==(Properties const&) const = default; - } m_properties; }; } diff --git a/Libraries/LibWeb/CSS/StyleValues/BorderRadiusRectStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/BorderRadiusRectStyleValue.cpp index 9f7b466d747d..3e3041d2509e 100644 --- a/Libraries/LibWeb/CSS/StyleValues/BorderRadiusRectStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/BorderRadiusRectStyleValue.cpp @@ -13,11 +13,11 @@ namespace Web::CSS { void BorderRadiusRectStyleValue::serialize(StringBuilder& builder, SerializationMode mode) const { auto horizontal_radii_serialized = serialize_a_positional_value_list( - { m_top_left->as_border_radius().horizontal_radius(), m_top_right->as_border_radius().horizontal_radius(), m_bottom_right->as_border_radius().horizontal_radius(), m_bottom_left->as_border_radius().horizontal_radius() }, + StyleValueVector { top_left()->as_border_radius().horizontal_radius(), top_right()->as_border_radius().horizontal_radius(), bottom_right()->as_border_radius().horizontal_radius(), bottom_left()->as_border_radius().horizontal_radius() }, mode); auto vertical_radii_serialized = serialize_a_positional_value_list( - { m_top_left->as_border_radius().vertical_radius(), m_top_right->as_border_radius().vertical_radius(), m_bottom_right->as_border_radius().vertical_radius(), m_bottom_left->as_border_radius().vertical_radius() }, + StyleValueVector { top_left()->as_border_radius().vertical_radius(), top_right()->as_border_radius().vertical_radius(), bottom_right()->as_border_radius().vertical_radius(), bottom_left()->as_border_radius().vertical_radius() }, mode); if (horizontal_radii_serialized == vertical_radii_serialized) { @@ -30,10 +30,10 @@ void BorderRadiusRectStyleValue::serialize(StringBuilder& builder, Serialization ValueComparingNonnullRefPtr BorderRadiusRectStyleValue::absolutized(ComputationContext const& computation_context) const { - auto top_left_absolutized = m_top_left->absolutized(computation_context); - auto top_right_absolutized = m_top_right->absolutized(computation_context); - auto bottom_right_absolutized = m_bottom_right->absolutized(computation_context); - auto bottom_left_absolutized = m_bottom_left->absolutized(computation_context); + auto top_left_absolutized = top_left()->absolutized(computation_context); + auto top_right_absolutized = top_right()->absolutized(computation_context); + auto bottom_right_absolutized = bottom_right()->absolutized(computation_context); + auto bottom_left_absolutized = bottom_left()->absolutized(computation_context); return BorderRadiusRectStyleValue::create(top_left_absolutized, top_right_absolutized, bottom_right_absolutized, bottom_left_absolutized); } diff --git a/Libraries/LibWeb/CSS/StyleValues/BorderRadiusRectStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/BorderRadiusRectStyleValue.h index 50dfe8bf563a..c1227963cb34 100644 --- a/Libraries/LibWeb/CSS/StyleValues/BorderRadiusRectStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/BorderRadiusRectStyleValue.h @@ -26,44 +26,35 @@ class BorderRadiusRectStyleValue final : public StyleValueWithDefaultOperators absolutized(ComputationContext const&) const override; + void serialize(StringBuilder&, SerializationMode) const; + ValueComparingNonnullRefPtr absolutized(ComputationContext const&) const; - NonnullRefPtr top_left() const { return m_top_left; } - NonnullRefPtr top_right() const { return m_top_right; } - NonnullRefPtr bottom_right() const { return m_bottom_right; } - NonnullRefPtr bottom_left() const { return m_bottom_left; } + ValueComparingNonnullRefPtr top_left() const { return *static_cast(m_value->border_radius_rect.top_left.pointer); } + ValueComparingNonnullRefPtr top_right() const { return *static_cast(m_value->border_radius_rect.top_right.pointer); } + ValueComparingNonnullRefPtr bottom_right() const { return *static_cast(m_value->border_radius_rect.bottom_right.pointer); } + ValueComparingNonnullRefPtr bottom_left() const { return *static_cast(m_value->border_radius_rect.bottom_left.pointer); } bool properties_equal(BorderRadiusRectStyleValue const& other) const { - return m_top_left == other.m_top_left - && m_top_right == other.m_top_right - && m_bottom_right == other.m_bottom_right - && m_bottom_left == other.m_bottom_left; + return top_left() == other.top_left() + && top_right() == other.top_right() + && bottom_right() == other.bottom_right() + && bottom_left() == other.bottom_left(); } - virtual bool is_computationally_independent() const override + bool is_computationally_independent() const { - return m_top_left->is_computationally_independent() - && m_top_right->is_computationally_independent() - && m_bottom_right->is_computationally_independent() - && m_bottom_left->is_computationally_independent(); + return top_left()->is_computationally_independent() + && top_right()->is_computationally_independent() + && bottom_right()->is_computationally_independent() + && bottom_left()->is_computationally_independent(); } private: BorderRadiusRectStyleValue(NonnullRefPtr top_left, NonnullRefPtr top_right, NonnullRefPtr bottom_right, NonnullRefPtr bottom_left) - : StyleValueWithDefaultOperators(Type::BorderRadiusRect) - , m_top_left(move(top_left)) - , m_top_right(move(top_right)) - , m_bottom_right(move(bottom_right)) - , m_bottom_left(move(bottom_left)) + : StyleValueWithDefaultOperators(Type::BorderRadiusRect, StyleValueFFI::rust_style_value_create_border_radius_rect(&top_left.leak_ref(), &top_right.leak_ref(), &bottom_right.leak_ref(), &bottom_left.leak_ref())) { } - - ValueComparingNonnullRefPtr m_top_left; - ValueComparingNonnullRefPtr m_top_right; - ValueComparingNonnullRefPtr m_bottom_right; - ValueComparingNonnullRefPtr m_bottom_left; }; } diff --git a/Libraries/LibWeb/CSS/StyleValues/BorderRadiusStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/BorderRadiusStyleValue.cpp index 63e2b9f8057f..94bd918932f5 100644 --- a/Libraries/LibWeb/CSS/StyleValues/BorderRadiusStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/BorderRadiusStyleValue.cpp @@ -13,21 +13,25 @@ namespace Web::CSS { void BorderRadiusStyleValue::serialize(StringBuilder& builder, SerializationMode mode) const { - if (m_properties.horizontal_radius == m_properties.vertical_radius) { - m_properties.horizontal_radius->serialize(builder, mode); + auto horizontal_radius = this->horizontal_radius(); + auto vertical_radius = this->vertical_radius(); + if (horizontal_radius == vertical_radius) { + horizontal_radius->serialize(builder, mode); return; } - m_properties.horizontal_radius->serialize(builder, mode); + horizontal_radius->serialize(builder, mode); builder.append(' '); - m_properties.vertical_radius->serialize(builder, mode); + vertical_radius->serialize(builder, mode); } ValueComparingNonnullRefPtr BorderRadiusStyleValue::absolutized(ComputationContext const& computation_context) const { - auto absolutized_horizontal_radius = m_properties.horizontal_radius->absolutized(computation_context); - auto absolutized_vertical_radius = m_properties.vertical_radius->absolutized(computation_context); + auto horizontal_radius = this->horizontal_radius(); + auto vertical_radius = this->vertical_radius(); + auto absolutized_horizontal_radius = horizontal_radius->absolutized(computation_context); + auto absolutized_vertical_radius = vertical_radius->absolutized(computation_context); - if (absolutized_vertical_radius == m_properties.vertical_radius && absolutized_horizontal_radius == m_properties.horizontal_radius) + if (absolutized_vertical_radius == vertical_radius && absolutized_horizontal_radius == horizontal_radius) return *this; return BorderRadiusStyleValue::create(absolutized_horizontal_radius, absolutized_vertical_radius); diff --git a/Libraries/LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h index 607c0f579c1f..cc80d31357b1 100644 --- a/Libraries/LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h @@ -28,30 +28,38 @@ class BorderRadiusStyleValue final : public StyleValueWithDefaultOperators const& horizontal_radius() const { return m_properties.horizontal_radius; } - ValueComparingNonnullRefPtr const& vertical_radius() const { return m_properties.vertical_radius; } - bool is_elliptical() const { return m_properties.is_elliptical; } + ValueComparingNonnullRefPtr horizontal_radius() const { return *static_cast(m_value->border_radius.horizontal_radius.pointer); } + ValueComparingNonnullRefPtr vertical_radius() const { return *static_cast(m_value->border_radius.vertical_radius.pointer); } + bool is_elliptical() const { return m_value->border_radius.is_elliptical; } - virtual void serialize(StringBuilder&, SerializationMode) const override; + void serialize(StringBuilder&, SerializationMode) const; - bool properties_equal(BorderRadiusStyleValue const& other) const { return m_properties == other.m_properties; } + bool properties_equal(BorderRadiusStyleValue const& other) const + { + return is_elliptical() == other.is_elliptical() + && horizontal_radius() == other.horizontal_radius() + && vertical_radius() == other.vertical_radius(); + } - virtual bool is_computationally_independent() const override { return m_properties.horizontal_radius->is_computationally_independent() && m_properties.vertical_radius->is_computationally_independent(); } + bool is_computationally_independent() const { return horizontal_radius()->is_computationally_independent() && vertical_radius()->is_computationally_independent(); } private: BorderRadiusStyleValue(ValueComparingNonnullRefPtr const& horizontal_radius, ValueComparingNonnullRefPtr const& vertical_radius) - : StyleValueWithDefaultOperators(Type::BorderRadius) - , m_properties { .is_elliptical = horizontal_radius != vertical_radius, .horizontal_radius = horizontal_radius, .vertical_radius = vertical_radius } + : StyleValueWithDefaultOperators(Type::BorderRadius, make_border_radius_data(horizontal_radius, vertical_radius)) + { + } + + static StyleValueFFI::StyleValueData* make_border_radius_data(ValueComparingNonnullRefPtr const& horizontal_radius, ValueComparingNonnullRefPtr const& vertical_radius) { + // The Rust allocation takes ownership of one strong reference to each radius. + return StyleValueFFI::rust_style_value_create_border_radius( + horizontal_radius != vertical_radius, + retain_style_value_for_rust(horizontal_radius.ptr()), retain_style_value_for_rust(vertical_radius.ptr())); } - virtual ValueComparingNonnullRefPtr absolutized(ComputationContext const&) const override; - struct Properties { - bool is_elliptical; - ValueComparingNonnullRefPtr horizontal_radius; - ValueComparingNonnullRefPtr vertical_radius; - bool operator==(Properties const&) const = default; - } m_properties; + // NB: StyleValue dispatches operations by type tag, so it may call private impls. + friend class StyleValue; + ValueComparingNonnullRefPtr absolutized(ComputationContext const&) const; }; } diff --git a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp index f1bb09b3577d..a4bccaf7100f 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp @@ -38,6 +38,48 @@ namespace Web::CSS { +StyleValueFFI::StyleValueData* CalculatedStyleValue::make_calculated_data(NonnullRefPtr const& calculation, NumericType const& resolved_type, CalculationContext const& context) +{ + // The Rust allocation takes ownership of one strong reference to the calculation node. + calculation->ref(); + static_assert(IsTriviallyCopyable); + auto resolved_type_bytes = bit_cast>(resolved_type); + Vector ranges; + ranges.ensure_capacity(context.accepted_ranges_by_type.size()); + for (auto const& [value_type, range] : context.accepted_ranges_by_type) + ranges.unchecked_append({ to_underlying(value_type), range.min, range.max }); + return StyleValueFFI::rust_style_value_create_calculated( + calculation.ptr(), + resolved_type_bytes.data(), resolved_type_bytes.size(), + context.percentages_resolve_as.has_value(), + context.percentages_resolve_as.has_value() ? to_underlying(*context.percentages_resolve_as) : 0, + context.resolve_numbers_as_integers, + ranges.data(), ranges.size()); +} + +NumericType CalculatedStyleValue::resolved_type() const +{ + auto const& blob = m_value->calculated.resolved_type; + Array bytes; + VERIFY(blob.length == bytes.size()); + __builtin_memcpy(bytes.data(), blob.pointer, bytes.size()); + return bit_cast(bytes); +} + +CalculationContext CalculatedStyleValue::calculation_context() const +{ + auto const& data = m_value->calculated; + CalculationContext context; + if (data.has_percentages_resolve_as) + context.percentages_resolve_as = static_cast(data.percentages_resolve_as); + context.resolve_numbers_as_integers = data.resolve_numbers_as_integers; + for (size_t i = 0; i < data.accepted_ranges.length; ++i) { + auto const& range = data.accepted_ranges.pointer[i]; + context.accepted_ranges_by_type.set(static_cast(range.value_type), NumericRange { range.min, range.max }); + } + return context; +} + CalculationContext CalculationContext::for_property(PropertyNameAndID const& property) { // FIXME: Handle registered custom properties, which may limit which types they accept. @@ -3129,12 +3171,15 @@ void CalculatedStyleValue::CalculationResult::invert() void CalculatedStyleValue::serialize(StringBuilder& builder, SerializationMode mode) const { - serialize_a_math_function(builder, *m_calculation, m_context, mode); + serialize_a_math_function(builder, *calculation(), calculation_context(), mode); } ValueComparingNonnullRefPtr CalculatedStyleValue::absolutized(ComputationContext const& computation_context) const { - auto simplified_calculation_tree = simplify_a_calculation_tree(m_calculation, m_context, CalculationResolutionContext::from_computation_context(computation_context)); + // NB: Materialize the context once; rebuilding it per use is a HashMap construction each time. + auto calculation_context = this->calculation_context(); + + auto simplified_calculation_tree = simplify_a_calculation_tree(calculation(), calculation_context, CalculationResolutionContext::from_computation_context(computation_context)); auto const simplified_percentage_dimension_mix = [&]() -> Optional> { // NOTE: A percentage dimension mix is a SumCalculationNode with two NumericCalculationNode children which have @@ -3159,7 +3204,7 @@ ValueComparingNonnullRefPtr CalculatedStyleValue::absolutized( if (!first_node.numeric_type()->percent_hint().has_value() || second_node.numeric_type()->percent_hint().has_value()) return {}; - auto dimension_component = try_get_value_with_canonical_unit(second_node, m_context, {}); + auto dimension_component = try_get_value_with_canonical_unit(second_node, calculation_context, {}); // https://drafts.csswg.org/css-values-4/#combine-mixed // The computed value of a percentage-dimension mix is defined as @@ -3173,7 +3218,7 @@ ValueComparingNonnullRefPtr CalculatedStyleValue::absolutized( if (simplified_percentage_dimension_mix.has_value()) return simplified_percentage_dimension_mix.value(); - return CalculatedStyleValue::create(simplified_calculation_tree, m_resolved_type, m_context); + return CalculatedStyleValue::create(simplified_calculation_tree, resolved_type(), calculation_context); } bool CalculatedStyleValue::equals(StyleValue const& other) const @@ -3181,25 +3226,30 @@ bool CalculatedStyleValue::equals(StyleValue const& other) const if (type() != other.type()) return false; - return m_calculation->equals(*other.as_calculated().m_calculation); + return calculation()->equals(*other.as_calculated().calculation()); } bool CalculatedStyleValue::is_computationally_independent() const { - return m_calculation->is_computationally_independent(); + return calculation()->is_computationally_independent(); } // https://drafts.csswg.org/css-values-4/#calc-computed-value Optional CalculatedStyleValue::resolve_value(CalculationResolutionContext const& resolution_context, bool apply_censoring_and_clamping) const +{ + return resolve_value(calculation_context(), resolution_context, apply_censoring_and_clamping); +} + +Optional CalculatedStyleValue::resolve_value(CalculationContext const& calculation_context, CalculationResolutionContext const& resolution_context, bool apply_censoring_and_clamping) const { // The calculation tree is again simplified at used value time; with used value time information. // NOTE: Any nodes which rely on dynamic state should have been simplified away in absolutized so we can pass a nullptr here - auto simplified_tree = simplify_a_calculation_tree(m_calculation, m_context, resolution_context); + auto simplified_tree = simplify_a_calculation_tree(calculation(), calculation_context, resolution_context); - if (!is(*simplified_tree) || (simplified_tree->contains_percentage() && m_context.percentages_resolve_as.has_value())) + if (!is(*simplified_tree) || (simplified_tree->contains_percentage() && calculation_context.percentages_resolve_as.has_value())) return {}; - auto value = try_get_value_with_canonical_unit(simplified_tree, m_context, resolution_context); + auto value = try_get_value_with_canonical_unit(simplified_tree, calculation_context, resolution_context); VERIFY(value.has_value()); @@ -3217,22 +3267,22 @@ Optional CalculatedStyleValue::resolve_valu // unable to sufficiently simplify the expression to allow range-checking. Optional accepted_range; - if (value->type()->matches_number(m_context.percentages_resolve_as)) - accepted_range = m_context.resolve_numbers_as_integers ? m_context.accepted_ranges_by_type.get(ValueType::Integer) : m_context.accepted_ranges_by_type.get(ValueType::Number); - else if (value->type()->matches_angle(m_context.percentages_resolve_as)) - accepted_range = m_context.accepted_ranges_by_type.get(ValueType::Angle); - else if (value->type()->matches_flex(m_context.percentages_resolve_as)) - accepted_range = m_context.accepted_ranges_by_type.get(ValueType::Flex); - else if (value->type()->matches_frequency(m_context.percentages_resolve_as)) - accepted_range = m_context.accepted_ranges_by_type.get(ValueType::Frequency); - else if (value->type()->matches_length(m_context.percentages_resolve_as)) - accepted_range = m_context.accepted_ranges_by_type.get(ValueType::Length); + if (value->type()->matches_number(calculation_context.percentages_resolve_as)) + accepted_range = calculation_context.resolve_numbers_as_integers ? calculation_context.accepted_ranges_by_type.get(ValueType::Integer) : calculation_context.accepted_ranges_by_type.get(ValueType::Number); + else if (value->type()->matches_angle(calculation_context.percentages_resolve_as)) + accepted_range = calculation_context.accepted_ranges_by_type.get(ValueType::Angle); + else if (value->type()->matches_flex(calculation_context.percentages_resolve_as)) + accepted_range = calculation_context.accepted_ranges_by_type.get(ValueType::Flex); + else if (value->type()->matches_frequency(calculation_context.percentages_resolve_as)) + accepted_range = calculation_context.accepted_ranges_by_type.get(ValueType::Frequency); + else if (value->type()->matches_length(calculation_context.percentages_resolve_as)) + accepted_range = calculation_context.accepted_ranges_by_type.get(ValueType::Length); else if (value->type()->matches_percentage()) - accepted_range = m_context.accepted_ranges_by_type.get(ValueType::Percentage); - else if (value->type()->matches_resolution(m_context.percentages_resolve_as)) - accepted_range = m_context.accepted_ranges_by_type.get(ValueType::Resolution); - else if (value->type()->matches_time(m_context.percentages_resolve_as)) - accepted_range = m_context.accepted_ranges_by_type.get(ValueType::Time); + accepted_range = calculation_context.accepted_ranges_by_type.get(ValueType::Percentage); + else if (value->type()->matches_resolution(calculation_context.percentages_resolve_as)) + accepted_range = calculation_context.accepted_ranges_by_type.get(ValueType::Resolution); + else if (value->type()->matches_time(calculation_context.percentages_resolve_as)) + accepted_range = calculation_context.accepted_ranges_by_type.get(ValueType::Time); if (!accepted_range.has_value()) { dbgln_if(LIBWEB_CSS_DEBUG, "FIXME: Calculation context missing accepted range {}", value->type()); @@ -3248,9 +3298,10 @@ Optional CalculatedStyleValue::resolve_valu Optional CalculatedStyleValue::resolve_angle(CalculationResolutionContext const& context) const { - auto result = resolve_value(context); + auto calculation_context = this->calculation_context(); + auto result = resolve_value(calculation_context, context); - if (result.has_value() && result->type.has_value() && result->type->matches_angle(m_context.percentages_resolve_as)) + if (result.has_value() && result->type.has_value() && result->type->matches_angle(calculation_context.percentages_resolve_as)) return Angle::make_degrees(result->value); return {}; @@ -3258,9 +3309,10 @@ Optional CalculatedStyleValue::resolve_angle(CalculationResolutionContext Optional CalculatedStyleValue::resolve_flex(CalculationResolutionContext const& context) const { - auto result = resolve_value(context); + auto calculation_context = this->calculation_context(); + auto result = resolve_value(calculation_context, context); - if (result.has_value() && result->type.has_value() && result->type->matches_flex(m_context.percentages_resolve_as)) + if (result.has_value() && result->type.has_value() && result->type->matches_flex(calculation_context.percentages_resolve_as)) return Flex::make_fr(result->value); return {}; @@ -3268,9 +3320,10 @@ Optional CalculatedStyleValue::resolve_flex(CalculationResolutionContext c Optional CalculatedStyleValue::resolve_frequency(CalculationResolutionContext const& context) const { - auto result = resolve_value(context); + auto calculation_context = this->calculation_context(); + auto result = resolve_value(calculation_context, context); - if (result.has_value() && result->type.has_value() && result->type->matches_frequency(m_context.percentages_resolve_as)) + if (result.has_value() && result->type.has_value() && result->type->matches_frequency(calculation_context.percentages_resolve_as)) return Frequency::make_hertz(result->value); return {}; @@ -3278,9 +3331,10 @@ Optional CalculatedStyleValue::resolve_frequency(CalculationResolutio Optional CalculatedStyleValue::resolve_length(CalculationResolutionContext const& context) const { - auto result = resolve_value(context); + auto calculation_context = this->calculation_context(); + auto result = resolve_value(calculation_context, context); - if (result.has_value() && result->type.has_value() && result->type->matches_length(m_context.percentages_resolve_as)) + if (result.has_value() && result->type.has_value() && result->type->matches_length(calculation_context.percentages_resolve_as)) return Length::make_px(result->value); return {}; @@ -3288,9 +3342,10 @@ Optional CalculatedStyleValue::resolve_length(CalculationResolutionConte Optional CalculatedStyleValue::resolve_raw_length(CalculationResolutionContext const& context) const { - auto result = resolve_value(context, false); + auto calculation_context = this->calculation_context(); + auto result = resolve_value(calculation_context, context, false); - if (result.has_value() && result->type.has_value() && result->type->matches_length(m_context.percentages_resolve_as)) + if (result.has_value() && result->type.has_value() && result->type->matches_length(calculation_context.percentages_resolve_as)) return result->value; return {}; @@ -3308,9 +3363,10 @@ Optional CalculatedStyleValue::resolve_percentage(CalculationResolut Optional CalculatedStyleValue::resolve_resolution(CalculationResolutionContext const& context) const { - auto result = resolve_value(context); + auto calculation_context = this->calculation_context(); + auto result = resolve_value(calculation_context, context); - if (result.has_value() && result->type.has_value() && result->type->matches_resolution(m_context.percentages_resolve_as)) + if (result.has_value() && result->type.has_value() && result->type->matches_resolution(calculation_context.percentages_resolve_as)) return Resolution::make_dots_per_pixel(result->value); return {}; @@ -3318,9 +3374,10 @@ Optional CalculatedStyleValue::resolve_resolution(CalculationResolut Optional