/* * Copyright (c) 2018-2024, Andreas Kling * Copyright (c) 2021-2024, Sam Atkins * Copyright (c) 2021, Tobias Christiansen * Copyright (c) 2022-2023, MacDue * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Web::CSS { CSSStyleValue::CSSStyleValue(Type type) : m_type(type) { } AbstractImageStyleValue const& CSSStyleValue::as_abstract_image() const { VERIFY(is_abstract_image()); return static_cast(*this); } AngleStyleValue const& CSSStyleValue::as_angle() const { VERIFY(is_angle()); return static_cast(*this); } BackgroundRepeatStyleValue const& CSSStyleValue::as_background_repeat() const { VERIFY(is_background_repeat()); return static_cast(*this); } BackgroundSizeStyleValue const& CSSStyleValue::as_background_size() const { VERIFY(is_background_size()); return static_cast(*this); } BasicShapeStyleValue const& CSSStyleValue::as_basic_shape() const { VERIFY(is_basic_shape()); return static_cast(*this); } BorderRadiusStyleValue const& CSSStyleValue::as_border_radius() const { VERIFY(is_border_radius()); return static_cast(*this); } CalculatedStyleValue const& CSSStyleValue::as_calculated() const { VERIFY(is_calculated()); return static_cast(*this); } CSSColorValue const& CSSStyleValue::as_color() const { VERIFY(is_color()); return static_cast(*this); } ColorSchemeStyleValue const& CSSStyleValue::as_color_scheme() const { VERIFY(is_color_scheme()); return static_cast(*this); } ConicGradientStyleValue const& CSSStyleValue::as_conic_gradient() const { VERIFY(is_conic_gradient()); return static_cast(*this); } ContentStyleValue const& CSSStyleValue::as_content() const { VERIFY(is_content()); return static_cast(*this); } CounterStyleValue const& CSSStyleValue::as_counter() const { VERIFY(is_counter()); return static_cast(*this); } CounterDefinitionsStyleValue const& CSSStyleValue::as_counter_definitions() const { VERIFY(is_counter_definitions()); return static_cast(*this); } CustomIdentStyleValue const& CSSStyleValue::as_custom_ident() const { VERIFY(is_custom_ident()); return static_cast(*this); } DisplayStyleValue const& CSSStyleValue::as_display() const { VERIFY(is_display()); return static_cast(*this); } EasingStyleValue const& CSSStyleValue::as_easing() const { VERIFY(is_easing()); return static_cast(*this); } EdgeStyleValue const& CSSStyleValue::as_edge() const { VERIFY(is_edge()); return static_cast(*this); } FilterValueListStyleValue const& CSSStyleValue::as_filter_value_list() const { VERIFY(is_filter_value_list()); return static_cast(*this); } FlexStyleValue const& CSSStyleValue::as_flex() const { VERIFY(is_flex()); return static_cast(*this); } FrequencyStyleValue const& CSSStyleValue::as_frequency() const { VERIFY(is_frequency()); return static_cast(*this); } GridAutoFlowStyleValue const& CSSStyleValue::as_grid_auto_flow() const { VERIFY(is_grid_auto_flow()); return static_cast(*this); } GridTemplateAreaStyleValue const& CSSStyleValue::as_grid_template_area() const { VERIFY(is_grid_template_area()); return static_cast(*this); } GridTrackPlacementStyleValue const& CSSStyleValue::as_grid_track_placement() const { VERIFY(is_grid_track_placement()); return static_cast(*this); } GridTrackSizeListStyleValue const& CSSStyleValue::as_grid_track_size_list() const { VERIFY(is_grid_track_size_list()); return static_cast(*this); } CSSKeywordValue const& CSSStyleValue::as_keyword() const { VERIFY(is_keyword()); return static_cast(*this); } ImageStyleValue const& CSSStyleValue::as_image() const { VERIFY(is_image()); return static_cast(*this); } IntegerStyleValue const& CSSStyleValue::as_integer() const { VERIFY(is_integer()); return static_cast(*this); } LengthStyleValue const& CSSStyleValue::as_length() const { VERIFY(is_length()); return static_cast(*this); } LinearGradientStyleValue const& CSSStyleValue::as_linear_gradient() const { VERIFY(is_linear_gradient()); return static_cast(*this); } MathDepthStyleValue const& CSSStyleValue::as_math_depth() const { VERIFY(is_math_depth()); return static_cast(*this); } NumberStyleValue const& CSSStyleValue::as_number() const { VERIFY(is_number()); return static_cast(*this); } OpenTypeTaggedStyleValue const& CSSStyleValue::as_open_type_tagged() const { VERIFY(is_open_type_tagged()); return static_cast(*this); } PercentageStyleValue const& CSSStyleValue::as_percentage() const { VERIFY(is_percentage()); return static_cast(*this); } PositionStyleValue const& CSSStyleValue::as_position() const { VERIFY(is_position()); return static_cast(*this); } RadialGradientStyleValue const& CSSStyleValue::as_radial_gradient() const { VERIFY(is_radial_gradient()); return static_cast(*this); } RatioStyleValue const& CSSStyleValue::as_ratio() const { VERIFY(is_ratio()); return static_cast(*this); } RectStyleValue const& CSSStyleValue::as_rect() const { VERIFY(is_rect()); return static_cast(*this); } ResolutionStyleValue const& CSSStyleValue::as_resolution() const { VERIFY(is_resolution()); return static_cast(*this); } ScrollbarGutterStyleValue const& CSSStyleValue::as_scrollbar_gutter() const { VERIFY(is_scrollbar_gutter()); return static_cast(*this); } ShadowStyleValue const& CSSStyleValue::as_shadow() const { VERIFY(is_shadow()); return static_cast(*this); } ShorthandStyleValue const& CSSStyleValue::as_shorthand() const { VERIFY(is_shorthand()); return static_cast(*this); } StringStyleValue const& CSSStyleValue::as_string() const { VERIFY(is_string()); return static_cast(*this); } TimeStyleValue const& CSSStyleValue::as_time() const { VERIFY(is_time()); return static_cast(*this); } TransformationStyleValue const& CSSStyleValue::as_transformation() const { VERIFY(is_transformation()); return static_cast(*this); } TransitionStyleValue const& CSSStyleValue::as_transition() const { VERIFY(is_transition()); return static_cast(*this); } UnresolvedStyleValue const& CSSStyleValue::as_unresolved() const { VERIFY(is_unresolved()); return static_cast(*this); } URLStyleValue const& CSSStyleValue::as_url() const { VERIFY(is_url()); return static_cast(*this); } StyleValueList const& CSSStyleValue::as_value_list() const { VERIFY(is_value_list()); return static_cast(*this); } ValueComparingNonnullRefPtr CSSStyleValue::absolutized(CSSPixelRect const&, Length::FontMetrics const&, Length::FontMetrics const&) const { return *this; } bool CSSStyleValue::has_auto() const { return is_keyword() && as_keyword().keyword() == Keyword::Auto; } int CSSStyleValue::to_font_weight() const { if (is_keyword()) { switch (as_keyword().keyword()) { case Keyword::Normal: return Gfx::FontWeight::Regular; case Keyword::Bold: return Gfx::FontWeight::Bold; case Keyword::Lighter: // FIXME: This should be relative to the parent. return Gfx::FontWeight::Regular; case Keyword::Bolder: // FIXME: This should be relative to the parent. return Gfx::FontWeight::Bold; default: return Gfx::FontWeight::Regular; } } if (is_number()) { return round_to(as_number().number()); } if (is_calculated()) { auto maybe_weight = as_calculated().resolve_integer({}); if (maybe_weight.has_value()) return maybe_weight.value(); } return Gfx::FontWeight::Regular; } int CSSStyleValue::to_font_slope() const { // FIXME: Implement oblique if (is_keyword()) { switch (as_keyword().keyword()) { case Keyword::Italic: { static int italic_slope = Gfx::name_to_slope("Italic"sv); return italic_slope; } case Keyword::Oblique: static int oblique_slope = Gfx::name_to_slope("Oblique"sv); return oblique_slope; case Keyword::Normal: default: break; } } static int normal_slope = Gfx::name_to_slope("Normal"sv); return normal_slope; } int CSSStyleValue::to_font_width() const { int width = Gfx::FontWidth::Normal; if (is_keyword()) { switch (as_keyword().keyword()) { case Keyword::UltraCondensed: width = Gfx::FontWidth::UltraCondensed; break; case Keyword::ExtraCondensed: width = Gfx::FontWidth::ExtraCondensed; break; case Keyword::Condensed: width = Gfx::FontWidth::Condensed; break; case Keyword::SemiCondensed: width = Gfx::FontWidth::SemiCondensed; break; case Keyword::Normal: width = Gfx::FontWidth::Normal; break; case Keyword::SemiExpanded: width = Gfx::FontWidth::SemiExpanded; break; case Keyword::Expanded: width = Gfx::FontWidth::Expanded; break; case Keyword::ExtraExpanded: width = Gfx::FontWidth::ExtraExpanded; break; case Keyword::UltraExpanded: width = Gfx::FontWidth::UltraExpanded; break; default: break; } } else if (is_percentage()) { float percentage = as_percentage().percentage().value(); if (percentage <= 50) { width = Gfx::FontWidth::UltraCondensed; } else if (percentage <= 62.5f) { width = Gfx::FontWidth::ExtraCondensed; } else if (percentage <= 75.0f) { width = Gfx::FontWidth::Condensed; } else if (percentage <= 87.5f) { width = Gfx::FontWidth::SemiCondensed; } else if (percentage <= 100.0f) { width = Gfx::FontWidth::Normal; } else if (percentage <= 112.5f) { width = Gfx::FontWidth::SemiExpanded; } else if (percentage <= 125.0f) { width = Gfx::FontWidth::Expanded; } else if (percentage <= 150.0f) { width = Gfx::FontWidth::ExtraExpanded; } else { width = Gfx::FontWidth::UltraExpanded; } } return width; } Optional CSSStyleValue::to_font_variant_alternates() const { VERIFY(is_keyword()); switch (as_keyword().keyword()) { case Keyword::Normal: return {}; case Keyword::HistoricalForms: return Gfx::FontVariantAlternates { .historical_forms = true }; default: VERIFY_NOT_REACHED(); } } Optional CSSStyleValue::to_font_variant_caps() const { VERIFY(is_keyword()); return keyword_to_font_variant_caps(as_keyword().keyword()); } Optional CSSStyleValue::to_font_variant_east_asian() const { VERIFY(is_value_list()); auto& list = as_value_list(); Gfx::FontVariantEastAsian east_asian {}; for (auto& value : list.values()) { VERIFY(value->is_keyword()); switch (value->as_keyword().keyword()) { case Keyword::Normal: return {}; case Keyword::Jis78: east_asian.variant = Gfx::FontVariantEastAsian::Variant::Jis78; break; case Keyword::Jis83: east_asian.variant = Gfx::FontVariantEastAsian::Variant::Jis83; break; case Keyword::Jis90: east_asian.variant = Gfx::FontVariantEastAsian::Variant::Jis90; break; case Keyword::Jis04: east_asian.variant = Gfx::FontVariantEastAsian::Variant::Jis04; break; case Keyword::Simplified: east_asian.variant = Gfx::FontVariantEastAsian::Variant::Simplified; break; case Keyword::Traditional: east_asian.variant = Gfx::FontVariantEastAsian::Variant::Traditional; break; case Keyword::FullWidth: east_asian.width = Gfx::FontVariantEastAsian::Width::FullWidth; break; case Keyword::ProportionalWidth: east_asian.width = Gfx::FontVariantEastAsian::Width::Proportional; break; case Keyword::Ruby: east_asian.ruby = true; break; default: VERIFY_NOT_REACHED(); break; } } return east_asian; } Optional CSSStyleValue::to_font_variant_emoji() const { VERIFY(is_keyword()); return keyword_to_font_variant_emoji(as_keyword().keyword()); } Optional CSSStyleValue::to_font_variant_ligatures() const { if (!is_value_list()) { return {}; } auto const& list = as_value_list(); Gfx::FontVariantLigatures ligatures {}; for (auto& value : list.values()) { if (!value->is_keyword()) continue; switch (value->as_keyword().keyword()) { case Keyword::Normal: return {}; case Keyword::None: ligatures.none = true; return ligatures; case Keyword::CommonLigatures: ligatures.common = Gfx::FontVariantLigatures::Common::Common; break; case Keyword::NoCommonLigatures: ligatures.common = Gfx::FontVariantLigatures::Common::NoCommon; break; case Keyword::DiscretionaryLigatures: ligatures.discretionary = Gfx::FontVariantLigatures::Discretionary::Discretionary; break; case Keyword::NoDiscretionaryLigatures: ligatures.discretionary = Gfx::FontVariantLigatures::Discretionary::NoDiscretionary; break; case Keyword::HistoricalLigatures: ligatures.historical = Gfx::FontVariantLigatures::Historical::Historical; break; case Keyword::NoHistoricalLigatures: ligatures.historical = Gfx::FontVariantLigatures::Historical::NoHistorical; break; case Keyword::Contextual: ligatures.contextual = Gfx::FontVariantLigatures::Contextual::Contextual; break; case Keyword::NoContextual: ligatures.contextual = Gfx::FontVariantLigatures::Contextual::NoContextual; break; default: VERIFY_NOT_REACHED(); break; } } return ligatures; } Optional CSSStyleValue::to_font_variant_numeric() const { VERIFY(is_value_list()); auto& list = as_value_list(); Gfx::FontVariantNumeric numeric {}; for (auto& value : list.values()) { VERIFY(value->is_keyword()); switch (value->as_keyword().keyword()) { case Keyword::Normal: return {}; case Keyword::Ordinal: numeric.ordinal = true; break; case Keyword::SlashedZero: numeric.slashed_zero = true; break; case Keyword::OldstyleNums: numeric.figure = Gfx::FontVariantNumeric::Figure::Oldstyle; break; case Keyword::LiningNums: numeric.figure = Gfx::FontVariantNumeric::Figure::Lining; break; case Keyword::ProportionalNums: numeric.spacing = Gfx::FontVariantNumeric::Spacing::Proportional; break; case Keyword::TabularNums: numeric.spacing = Gfx::FontVariantNumeric::Spacing::Tabular; break; case Keyword::DiagonalFractions: numeric.fraction = Gfx::FontVariantNumeric::Fraction::Diagonal; break; case Keyword::StackedFractions: numeric.fraction = Gfx::FontVariantNumeric::Fraction::Stacked; break; default: VERIFY_NOT_REACHED(); break; } } return numeric; } Optional CSSStyleValue::to_font_variant_position() const { VERIFY(is_keyword()); return keyword_to_font_variant_position(as_keyword().keyword()); } }