/* * Copyright (c) 2018-2023, Andreas Kling * Copyright (c) 2021, Tobias Christiansen * Copyright (c) 2021-2025, Sam Atkins * Copyright (c) 2022-2023, MacDue * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Web::CSS { #define ENUMERATE_CSS_STYLE_VALUE_TYPES \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Anchor, anchor, AnchorStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(AnchorSize, anchor_size, AnchorSizeStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Angle, angle, AngleStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(BackgroundSize, background_size, BackgroundSizeStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(BasicShape, basic_shape, BasicShapeStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(BorderImageSlice, border_image_slice, BorderImageSliceStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(BorderRadius, border_radius, BorderRadiusStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Calculated, calculated, CalculatedStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Color, color, CSSColorValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(ColorScheme, color_scheme, ColorSchemeStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(ConicGradient, conic_gradient, ConicGradientStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Content, content, ContentStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Counter, counter, CounterStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(CounterDefinitions, counter_definitions, CounterDefinitionsStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Cursor, cursor, CursorStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(CustomIdent, custom_ident, CustomIdentStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Display, display, DisplayStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Easing, easing, EasingStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Edge, edge, EdgeStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(FilterValueList, filter_value_list, FilterValueListStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(FitContent, fit_content, FitContentStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Flex, flex, FlexStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(FontSource, font_source, FontSourceStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(FontStyle, font_style, FontStyleStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Frequency, frequency, FrequencyStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(GridAutoFlow, grid_auto_flow, GridAutoFlowStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(GridTemplateArea, grid_template_area, GridTemplateAreaStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(GridTrackPlacement, grid_track_placement, GridTrackPlacementStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(GridTrackSizeList, grid_track_size_list, GridTrackSizeListStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(GuaranteedInvalid, guaranteed_invalid, GuaranteedInvalidStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Image, image, ImageStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Integer, integer, IntegerStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Keyword, keyword, CSSKeywordValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Length, length, LengthStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(LinearGradient, linear_gradient, LinearGradientStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(MathDepth, math_depth, MathDepthStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Number, number, NumberStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(OpenTypeTagged, open_type_tagged, OpenTypeTaggedStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(PendingSubstitution, pending_substitution, PendingSubstitutionStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Percentage, percentage, PercentageStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Position, position, PositionStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(RadialGradient, radial_gradient, RadialGradientStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Ratio, ratio, RatioStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Rect, rect, RectStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(RepeatStyle, repeat_style, RepeatStyleStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Resolution, resolution, ResolutionStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(ScrollbarColor, scrollbar_color, ScrollbarColorStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(ScrollbarGutter, scrollbar_gutter, ScrollbarGutterStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Shadow, shadow, ShadowStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Shorthand, shorthand, ShorthandStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(String, string, StringStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Time, time, TimeStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Transformation, transformation, TransformationStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Transition, transition, TransitionStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(UnicodeRange, unicode_range, UnicodeRangeStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(Unresolved, unresolved, UnresolvedStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(URL, url, URLStyleValue) \ __ENUMERATE_CSS_STYLE_VALUE_TYPE(ValueList, value_list, StyleValueList) template struct ValueComparingNonnullRefPtr : public NonnullRefPtr { using NonnullRefPtr::NonnullRefPtr; ValueComparingNonnullRefPtr(NonnullRefPtr const& other) : NonnullRefPtr(other) { } ValueComparingNonnullRefPtr(NonnullRefPtr&& other) : NonnullRefPtr(move(other)) { } bool operator==(ValueComparingNonnullRefPtr const& other) const { return this->ptr() == other.ptr() || this->ptr()->equals(*other); } private: using NonnullRefPtr::operator==; }; template struct ValueComparingRefPtr : public RefPtr { using RefPtr::RefPtr; ValueComparingRefPtr(RefPtr const& other) : RefPtr(other) { } ValueComparingRefPtr(RefPtr&& other) : RefPtr(move(other)) { } template bool operator==(ValueComparingNonnullRefPtr const& other) const { return this->ptr() == other.ptr() || (this->ptr() && this->ptr()->equals(*other)); } bool operator==(ValueComparingRefPtr const& other) const { return this->ptr() == other.ptr() || (this->ptr() && other.ptr() && this->ptr()->equals(*other)); } private: using RefPtr::operator==; }; using StyleValueVector = Vector>; struct ColorResolutionContext { Optional color_scheme; Optional current_color; GC::Ptr document; CalculationResolutionContext calculation_resolution_context; [[nodiscard]] static ColorResolutionContext for_element(DOM::AbstractElement const&); [[nodiscard]] static ColorResolutionContext for_layout_node_with_style(Layout::NodeWithStyle const&); }; // https://drafts.css-houdini.org/css-typed-om-1/#cssstylevalue class CSSStyleValue : public RefCounted { public: virtual ~CSSStyleValue() = default; enum class Type { #define __ENUMERATE_CSS_STYLE_VALUE_TYPE(title_case, snake_case, style_value_class_name) title_case, ENUMERATE_CSS_STYLE_VALUE_TYPES #undef __ENUMERATE_CSS_STYLE_VALUE_TYPE }; Type type() const { return m_type; } bool is_abstract_image() const { return AK::first_is_one_of(type(), Type::Image, Type::LinearGradient, Type::ConicGradient, Type::RadialGradient); } AbstractImageStyleValue const& as_abstract_image() const; AbstractImageStyleValue& as_abstract_image() { return const_cast(const_cast(*this).as_abstract_image()); } virtual bool is_color_function() const { return false; } #define __ENUMERATE_CSS_STYLE_VALUE_TYPE(title_case, snake_case, style_value_class_name) \ bool is_##snake_case() const { return type() == Type::title_case; } \ style_value_class_name const& as_##snake_case() const; \ style_value_class_name& as_##snake_case() { return const_cast(const_cast(*this).as_##snake_case()); } ENUMERATE_CSS_STYLE_VALUE_TYPES #undef __ENUMERATE_CSS_STYLE_VALUE_TYPE // https://www.w3.org/TR/css-values-4/#common-keywords // https://drafts.csswg.org/css-cascade-4/#valdef-all-revert bool is_css_wide_keyword() const { return is_inherit() || is_initial() || is_revert() || is_unset() || is_revert_layer(); } bool is_inherit() const { return to_keyword() == Keyword::Inherit; } bool is_initial() const { return to_keyword() == Keyword::Initial; } bool is_revert() const { return to_keyword() == Keyword::Revert; } bool is_revert_layer() const { return to_keyword() == Keyword::RevertLayer; } bool is_unset() const { return to_keyword() == Keyword::Unset; } bool has_auto() const; virtual bool has_color() const { return false; } virtual ValueComparingNonnullRefPtr absolutized(CSSPixelRect const& viewport_rect, Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const; virtual Optional to_color(ColorResolutionContext) const { return {}; } Keyword to_keyword() const; virtual String to_string(SerializationMode) const = 0; virtual Vector tokenize() const; [[nodiscard]] int to_font_weight() const; [[nodiscard]] int to_font_slope() const; [[nodiscard]] int to_font_width() const; virtual void set_style_sheet(GC::Ptr) { } virtual void visit_edges(JS::Cell::Visitor&) const { } virtual bool equals(CSSStyleValue const& other) const = 0; bool operator==(CSSStyleValue const& other) const { return this->equals(other); } protected: explicit CSSStyleValue(Type); private: Type m_type; }; template struct StyleValueWithDefaultOperators : public CSSStyleValue { using CSSStyleValue::CSSStyleValue; using Base = CSSStyleValue; virtual bool equals(CSSStyleValue const& other) const override { if (type() != other.type()) return false; auto const& typed_other = static_cast(other); return static_cast(*this).properties_equal(typed_other); } }; } template<> struct AK::Formatter : Formatter { ErrorOr format(FormatBuilder& builder, Web::CSS::CSSStyleValue const& style_value) { return Formatter::format(builder, style_value.to_string(Web::CSS::SerializationMode::Normal)); } };