LibWeb: Style font-variant properties

This commit is contained in:
Johan Dahlin 2024-11-11 22:49:02 +01:00
parent 164dd05467
commit 0a3193f0b6
14 changed files with 781 additions and 198 deletions

View file

@ -16,6 +16,7 @@ set(SOURCES
Font/Font.cpp
Font/FontData.cpp
Font/FontDatabase.cpp
Font/FontVariant.cpp
Font/PathFontProvider.cpp
Font/ScaledFont.cpp
Font/ScaledFontSkia.cpp

View file

@ -0,0 +1,176 @@
/*
* Copyright (c) 2024, Johan Dahlin <jdahlin@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <LibGfx/Font/FontVariant.h>
namespace Gfx {
StringView font_variant_alternates_to_string(FontVariantAlternates value)
{
if (value.normal && value.historical_forms)
return "normal historical-forms"sv;
if (value.normal)
return "normal"sv;
if (value.historical_forms)
return "historical-forms"sv;
return {};
}
StringView font_variant_ligatures_to_string(FontVariantLigatures ligatures)
{
if (ligatures.normal)
return "normal"sv;
if (ligatures.none)
return "none"sv;
Vector<StringView> values;
switch (ligatures.common) {
case FontVariantLigatures::Common::Common:
values.append("common-ligatures"sv);
break;
case FontVariantLigatures::Common::NoCommon:
values.append("no-common-ligatures"sv);
break;
case FontVariantLigatures::Common::Unset:
break;
}
switch (ligatures.discretionary) {
case FontVariantLigatures::Discretionary::Discretionary:
values.append("discretionary-ligatures"sv);
break;
case FontVariantLigatures::Discretionary::NoDiscretionary:
values.append("no-discretionary-ligatures"sv);
break;
case FontVariantLigatures::Discretionary::Unset:
break;
}
switch (ligatures.historical) {
case FontVariantLigatures::Historical::Historical:
values.append("historical-ligatures"sv);
break;
case FontVariantLigatures::Historical::NoHistorical:
values.append("no-historical-ligatures"sv);
break;
case FontVariantLigatures::Historical::Unset:
break;
}
switch (ligatures.contextual) {
case FontVariantLigatures::Contextual::Contextual:
values.append("contextual"sv);
break;
case FontVariantLigatures::Contextual::NoContextual:
values.append("no-contextual"sv);
break;
case FontVariantLigatures::Contextual::Unset:
break;
}
StringBuilder builder;
builder.join(' ', values);
return MUST(builder.to_string());
}
StringView font_variant_east_asian_to_string(FontVariantEastAsian value)
{
Vector<StringView> values;
switch (value.variant) {
case FontVariantEastAsian::Variant::Unset:
break;
case FontVariantEastAsian::Variant::Jis78:
values.append("jis78"sv);
break;
case FontVariantEastAsian::Variant::Jis83:
values.append("jis83"sv);
break;
case FontVariantEastAsian::Variant::Jis90:
values.append("jis90"sv);
break;
case FontVariantEastAsian::Variant::Jis04:
values.append("jis04"sv);
break;
case FontVariantEastAsian::Variant::Simplified:
values.append("simplified"sv);
break;
case FontVariantEastAsian::Variant::Traditional:
values.append("traditional"sv);
break;
}
switch (value.width) {
case FontVariantEastAsian::Width::Unset:
break;
case FontVariantEastAsian::Width::FullWidth:
values.append("full-width"sv);
break;
case FontVariantEastAsian::Width::Proportional:
values.append("proportional-width"sv);
break;
}
if (value.ruby)
values.append("ruby"sv);
StringBuilder builder;
builder.join(' ', values);
return MUST(builder.to_string());
}
StringView font_variant_numeric_to_string(FontVariantNumeric value)
{
Vector<StringView> values;
if (value.normal)
values.append("normal"sv);
if (value.ordinal)
values.append("ordinal"sv);
if (value.slashed_zero)
values.append("slashed-zero"sv);
switch (value.figure) {
case FontVariantNumeric::Figure::Unset:
break;
case FontVariantNumeric::Figure::Lining:
values.append("lining-nums"sv);
break;
case FontVariantNumeric::Figure::Oldstyle:
values.append("oldstyle-nums"sv);
break;
}
switch (value.spacing) {
case FontVariantNumeric::Spacing::Unset:
break;
case FontVariantNumeric::Spacing::Proportional:
values.append("proportional-nums"sv);
break;
case FontVariantNumeric::Spacing::Tabular:
values.append("tabular-nums"sv);
break;
}
switch (value.fraction) {
case FontVariantNumeric::Fraction::Unset:
break;
case FontVariantNumeric::Fraction::Diagonal:
values.append("diagonal-fractions"sv);
break;
case FontVariantNumeric::Fraction::Stacked:
values.append("stacked-fractions"sv);
break;
}
StringBuilder builder;
builder.join(' ', values);
return MUST(builder.to_string());
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Optional.h>
#include <AK/StringView.h>
#include <AK/Vector.h>
#pragma once
namespace Gfx {
using FontFeatureName = StringView;
class FontVariantAlternates {
public:
bool normal { false };
bool historical_forms { false };
};
class FontVariantEastAsian {
public:
enum class Variant { Unset,
Jis78,
Jis83,
Jis90,
Jis04,
Simplified,
Traditional };
enum class Width { Unset,
Proportional,
FullWidth };
bool normal = false;
bool ruby = false;
Variant variant { Variant::Unset };
Width width { Width::Unset };
};
class FontVariantLigatures {
public:
enum class Common { Unset,
Common,
NoCommon };
enum class Discretionary { Unset,
Discretionary,
NoDiscretionary };
enum class Historical { Unset,
Historical,
NoHistorical };
enum class Contextual { Unset,
Contextual,
NoContextual };
bool normal = false;
bool none = false;
Common common { Common::Unset };
Discretionary discretionary { Discretionary::Unset };
Historical historical { Historical::Unset };
Contextual contextual { Contextual::Unset };
};
class FontVariantNumeric {
public:
enum class Figure { Unset,
Lining,
Oldstyle };
enum class Spacing { Unset,
Proportional,
Tabular };
enum class Fraction { Unset,
Diagonal,
Stacked };
bool normal = false;
bool ordinal = false;
bool slashed_zero = false;
Figure figure { Figure::Unset };
Spacing spacing { Spacing::Unset };
Fraction fraction { Fraction::Unset };
};
extern StringView font_variant_alternates_to_string(FontVariantAlternates);
extern StringView font_variant_east_asian_to_string(FontVariantEastAsian);
extern StringView font_variant_ligatures_to_string(FontVariantLigatures);
extern StringView font_variant_numeric_to_string(FontVariantNumeric);
}

View file

@ -30,6 +30,16 @@ struct DrawGlyph {
}
};
/* ABI compatible with harfbuzz' hb_feature_t */
typedef struct ShapeFeature {
u32 tag;
u32 value;
unsigned int start;
unsigned int end;
} ShapeFeature;
using ShapeFeatures = Vector<ShapeFeature, 4>;
class GlyphRun : public RefCounted<GlyphRun> {
public:
enum class TextType {

View file

@ -481,4 +481,165 @@ int CSSStyleValue::to_font_width() const
return width;
}
Gfx::FontVariantAlternates CSSStyleValue::to_font_variant_alternates() const
{
VERIFY(is_keyword());
switch (as_keyword().keyword()) {
case Keyword::Normal:
return Gfx::FontVariantAlternates { .normal = true };
case Keyword::HistoricalForms:
return Gfx::FontVariantAlternates { .historical_forms = true };
default:
VERIFY_NOT_REACHED();
}
}
Optional<FontVariantCaps> CSSStyleValue::to_font_variant_caps() const
{
VERIFY(is_keyword());
return keyword_to_font_variant_caps(as_keyword().keyword());
}
Gfx::FontVariantEastAsian 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:
east_asian.normal = true;
return east_asian;
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;
}
Gfx::FontVariantLigatures CSSStyleValue::to_font_variant_ligatures() const
{
VERIFY(is_value_list());
auto& list = as_value_list();
Gfx::FontVariantLigatures ligatures;
for (auto& value : list.values()) {
VERIFY(value->is_keyword());
switch (value->as_keyword().keyword()) {
case Keyword::Normal:
ligatures.normal = true;
return ligatures;
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;
}
Gfx::FontVariantNumeric 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:
numeric.normal = true;
return numeric;
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<FontVariantPosition> CSSStyleValue::to_font_variant_position() const
{
VERIFY(is_keyword());
return keyword_to_font_variant_position(as_keyword().keyword());
}
}

View file

@ -20,6 +20,7 @@
#include <AK/Vector.h>
#include <AK/WeakPtr.h>
#include <LibGfx/Color.h>
#include <LibGfx/Font/FontVariant.h>
#include <LibURL/URL.h>
#include <LibWeb/CSS/Enums.h>
#include <LibWeb/CSS/Keyword.h>
@ -104,6 +105,7 @@ public:
Edge,
FilterValueList,
Flex,
FontVariant,
Frequency,
GridAutoFlow,
GridTemplateArea,
@ -355,6 +357,12 @@ public:
[[nodiscard]] int to_font_weight() const;
[[nodiscard]] int to_font_slope() const;
[[nodiscard]] int to_font_width() const;
[[nodiscard]] Gfx::FontVariantAlternates to_font_variant_alternates() const;
[[nodiscard]] Optional<FontVariantCaps> to_font_variant_caps() const;
[[nodiscard]] Gfx::FontVariantEastAsian to_font_variant_east_asian() const;
[[nodiscard]] Gfx::FontVariantLigatures to_font_variant_ligatures() const;
[[nodiscard]] Gfx::FontVariantNumeric to_font_variant_numeric() const;
[[nodiscard]] Optional<FontVariantPosition> to_font_variant_position() const;
virtual bool equals(CSSStyleValue const& other) const = 0;

View file

@ -97,7 +97,6 @@ public:
static AspectRatio aspect_ratio() { return AspectRatio { true, {} }; }
static CSSPixels font_size() { return 16; }
static int font_weight() { return 400; }
static CSS::FontVariant font_variant() { return CSS::FontVariant::Normal; }
static CSSPixels line_height() { return 0; }
static CSS::Float float_() { return CSS::Float::None; }
static CSS::Length border_spacing() { return CSS::Length::make_px(0); }
@ -511,7 +510,12 @@ public:
Gfx::FontCascadeList const& font_list() const { return *m_inherited.font_list; }
CSSPixels font_size() const { return m_inherited.font_size; }
int font_weight() const { return m_inherited.font_weight; }
CSS::FontVariant font_variant() const { return m_inherited.font_variant; }
Gfx::FontVariantAlternates font_variant_alternates() const { return m_inherited.font_variant_alternates; }
FontVariantCaps font_variant_caps() const { return m_inherited.font_variant_caps; }
Gfx::FontVariantEastAsian font_variant_east_asian() const { return m_inherited.font_variant_east_asian; }
Gfx::FontVariantLigatures font_variant_ligatures() const { return m_inherited.font_variant_ligatures; }
Gfx::FontVariantNumeric font_variant_numeric() const { return m_inherited.font_variant_numeric; }
FontVariantPosition font_variant_position() const { return m_inherited.font_variant_position; }
Optional<FlyString> font_language_override() const { return m_inherited.font_language_override; }
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings() const { return m_inherited.font_feature_settings; }
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const { return m_inherited.font_variation_settings; }
@ -545,7 +549,12 @@ protected:
RefPtr<Gfx::FontCascadeList> font_list {};
CSSPixels font_size { InitialValues::font_size() };
int font_weight { InitialValues::font_weight() };
CSS::FontVariant font_variant { InitialValues::font_variant() };
Gfx::FontVariantAlternates font_variant_alternates { .normal = true };
FontVariantCaps font_variant_caps { FontVariantCaps::Normal };
Gfx::FontVariantEastAsian font_variant_east_asian { .normal = true };
Gfx::FontVariantLigatures font_variant_ligatures { .normal = true };
Gfx::FontVariantNumeric font_variant_numeric { .normal = true };
FontVariantPosition font_variant_position { FontVariantPosition::Normal };
Optional<FlyString> font_language_override;
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings;
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings;
@ -717,7 +726,12 @@ public:
void set_font_list(NonnullRefPtr<Gfx::FontCascadeList> font_list) { m_inherited.font_list = move(font_list); }
void set_font_size(CSSPixels font_size) { m_inherited.font_size = font_size; }
void set_font_weight(int font_weight) { m_inherited.font_weight = font_weight; }
void set_font_variant(CSS::FontVariant font_variant) { m_inherited.font_variant = font_variant; }
void set_font_variant_alternates(Gfx::FontVariantAlternates font_variant_alternates) { m_inherited.font_variant_alternates = font_variant_alternates; }
void set_font_variant_caps(FontVariantCaps font_variant_caps) { m_inherited.font_variant_caps = font_variant_caps; }
void set_font_variant_east_asian(Gfx::FontVariantEastAsian font_variant_east_asian) { m_inherited.font_variant_east_asian = font_variant_east_asian; }
void set_font_variant_ligatures(Gfx::FontVariantLigatures font_variant_ligatures) { m_inherited.font_variant_ligatures = font_variant_ligatures; }
void set_font_variant_numeric(Gfx::FontVariantNumeric font_variant_numeric) { m_inherited.font_variant_numeric = font_variant_numeric; }
void set_font_variant_position(FontVariantPosition font_variant_position) { m_inherited.font_variant_position = font_variant_position; }
void set_font_language_override(Optional<FlyString> font_language_override) { m_inherited.font_language_override = font_language_override; }
void set_font_feature_settings(Optional<HashMap<FlyString, IntegerOrCalculated>> value) { m_inherited.font_feature_settings = move(value); }
void set_font_variation_settings(Optional<HashMap<FlyString, NumberOrCalculated>> value) { m_inherited.font_variation_settings = move(value); }

View file

@ -2111,6 +2111,13 @@ void StyleComputer::compute_font(StyleProperties& style, DOM::Element const* ele
compute_defaulted_property_value(style, element, CSS::PropertyID::FontStyle, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontWeight, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::LineHeight, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariant, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantAlternates, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantCaps, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantEastAsian, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantLigatures, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantNumeric, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantPosition, pseudo_element);
auto const& font_family = style.property(CSS::PropertyID::FontFamily);
auto const& font_size = style.property(CSS::PropertyID::FontSize);

View file

@ -1143,12 +1143,6 @@ Variant<CSS::VerticalAlign, CSS::LengthPercentage> StyleProperties::vertical_ali
VERIFY_NOT_REACHED();
}
Optional<CSS::FontVariant> StyleProperties::font_variant() const
{
auto const& value = property(CSS::PropertyID::FontVariant);
return keyword_to_font_variant(value.to_keyword());
}
Optional<FlyString> StyleProperties::font_language_override() const
{
auto const& value = property(CSS::PropertyID::FontLanguageOverride);
@ -1157,6 +1151,42 @@ Optional<FlyString> StyleProperties::font_language_override() const
return {};
}
Gfx::FontVariantAlternates StyleProperties::font_variant_alternates() const
{
auto const& value = property(CSS::PropertyID::FontVariantAlternates);
return value.to_font_variant_alternates();
}
Optional<FontVariantCaps> StyleProperties::font_variant_caps() const
{
auto const& value = property(CSS::PropertyID::FontVariantCaps);
return value.to_font_variant_caps();
}
Gfx::FontVariantEastAsian StyleProperties::font_variant_east_asian() const
{
auto const& value = property(CSS::PropertyID::FontVariantEastAsian);
return value.to_font_variant_east_asian();
}
Gfx::FontVariantLigatures StyleProperties::font_variant_ligatures() const
{
auto const& value = property(CSS::PropertyID::FontVariantLigatures);
return value.to_font_variant_ligatures();
}
Gfx::FontVariantNumeric StyleProperties::font_variant_numeric() const
{
auto const& value = property(CSS::PropertyID::FontVariantNumeric);
return value.to_font_variant_numeric();
}
Optional<FontVariantPosition> StyleProperties::font_variant_position() const
{
auto const& value = property(CSS::PropertyID::FontVariantPosition);
return value.to_font_variant_position();
}
Optional<HashMap<FlyString, IntegerOrCalculated>> StyleProperties::font_feature_settings() const
{
auto const& value = property(PropertyID::FontFeatureSettings);

View file

@ -149,7 +149,12 @@ public:
Optional<CSS::BoxSizing> box_sizing() const;
Optional<CSS::PointerEvents> pointer_events() const;
Variant<CSS::VerticalAlign, CSS::LengthPercentage> vertical_align() const;
Optional<CSS::FontVariant> font_variant() const;
Gfx::FontVariantAlternates font_variant_alternates() const;
Optional<FontVariantCaps> font_variant_caps() const;
Gfx::FontVariantEastAsian font_variant_east_asian() const;
Gfx::FontVariantLigatures font_variant_ligatures() const;
Gfx::FontVariantNumeric font_variant_numeric() const;
Optional<FontVariantPosition> font_variant_position() const;
Optional<FlyString> font_language_override() const;
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings() const;
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const;

View file

@ -119,6 +119,60 @@ String ShorthandStyleValue::to_string() const
longhand(PropertyID::FontSize)->to_string(),
longhand(PropertyID::LineHeight)->to_string(),
longhand(PropertyID::FontFamily)->to_string()));
case PropertyID::FontVariant: {
Vector<StringView> values;
auto alternates = longhand(PropertyID::FontVariantAlternates)->to_font_variant_alternates();
if (alternates.historical_forms)
values.append("historical-forms"sv);
auto caps_or_null = longhand(PropertyID::FontVariantCaps)->to_font_variant_caps();
if (caps_or_null.has_value() && caps_or_null.value() != CSS::FontVariantCaps::Normal) {
values.append(CSS::to_string(caps_or_null.release_value()));
}
auto east_asian = longhand(PropertyID::FontVariantEastAsian)->to_font_variant_east_asian();
if (!east_asian.normal) {
if (east_asian.variant != Gfx::FontVariantEastAsian::Variant::Unset)
values.append(Gfx::font_variant_east_asian_to_string(east_asian));
if (east_asian.width != Gfx::FontVariantEastAsian::Width::Unset)
values.append(Gfx::font_variant_east_asian_to_string(east_asian));
}
auto ligatures = longhand(PropertyID::FontVariantLigatures)->to_font_variant_ligatures();
if (!ligatures.normal && !ligatures.none) {
if (ligatures.common != Gfx::FontVariantLigatures::Common::Unset)
values.append(Gfx::font_variant_ligatures_to_string(ligatures));
if (ligatures.discretionary != Gfx::FontVariantLigatures::Discretionary::Unset) {
values.append(Gfx::font_variant_ligatures_to_string(ligatures));
}
if (ligatures.historical != Gfx::FontVariantLigatures::Historical::Unset) {
values.append(Gfx::font_variant_ligatures_to_string(ligatures));
}
if (ligatures.contextual != Gfx::FontVariantLigatures::Contextual::Unset) {
values.append(Gfx::font_variant_ligatures_to_string(ligatures));
}
}
auto numeric = longhand(PropertyID::FontVariantNumeric)->to_font_variant_numeric();
if (!numeric.normal) {
if (numeric.ordinal)
values.append("ordinal"sv);
if (numeric.slashed_zero)
values.append("slashed-zero"sv);
if (numeric.figure != Gfx::FontVariantNumeric::Figure::Unset)
values.append(Gfx::font_variant_numeric_to_string(numeric));
if (numeric.spacing != Gfx::FontVariantNumeric::Spacing::Unset)
values.append(Gfx::font_variant_numeric_to_string(numeric));
if (numeric.fraction != Gfx::FontVariantNumeric::Fraction::Unset)
values.append(Gfx::font_variant_numeric_to_string(numeric));
}
auto position_or_null = longhand(PropertyID::FontVariantPosition)->to_font_variant_position();
if (position_or_null.has_value() && position_or_null.value() != CSS::FontVariantPosition::Normal) {
values.append(CSS::to_string(position_or_null.release_value()));
}
StringBuilder builder;
if (values.is_empty())
builder.append("normal"sv);
else
builder.join(' ', values);
return MUST(builder.to_string());
}
case PropertyID::GridArea: {
auto& row_start = longhand(PropertyID::GridRowStart)->as_grid_track_placement();
auto& column_start = longhand(PropertyID::GridColumnStart)->as_grid_track_placement();

View file

@ -1,6 +1,6 @@
All supported properties and their default values exposed from CSSStyleDeclaration from getComputedStyle:
'cssText': ''
'length': '203'
'length': '210'
'parentRule': 'null'
'cssFloat': 'none'
'WebkitAlignContent': 'normal'
@ -305,6 +305,20 @@ All supported properties and their default values exposed from CSSStyleDeclarati
'font-style': 'normal'
'fontVariant': 'normal'
'font-variant': 'normal'
'fontVariantAlternates': 'normal'
'font-variant-alternates': 'normal'
'fontVariantCaps': 'normal'
'font-variant-caps': 'normal'
'fontVariantEastAsian': 'normal'
'font-variant-east-asian': 'normal'
'fontVariantEmoji': 'normal'
'font-variant-emoji': 'normal'
'fontVariantLigatures': 'normal'
'font-variant-ligatures': 'normal'
'fontVariantNumeric': 'normal'
'font-variant-numeric': 'normal'
'fontVariantPosition': 'normal'
'font-variant-position': 'normal'
'fontVariationSettings': 'normal'
'font-variation-settings': 'normal'
'fontWeight': '400'

View file

@ -18,191 +18,197 @@ All properties associated with getComputedStyle(document.body):
"15": "font-size",
"16": "font-style",
"17": "font-variant",
"18": "font-variation-settings",
"19": "font-weight",
"20": "font-width",
"21": "image-rendering",
"22": "letter-spacing",
"23": "line-height",
"24": "list-style-image",
"25": "list-style-position",
"26": "list-style-type",
"27": "math-depth",
"28": "math-shift",
"29": "math-style",
"30": "pointer-events",
"31": "quotes",
"32": "stroke",
"33": "stroke-dashoffset",
"34": "stroke-linecap",
"35": "stroke-linejoin",
"36": "stroke-miterlimit",
"37": "stroke-opacity",
"38": "stroke-width",
"39": "tab-size",
"40": "text-align",
"41": "text-anchor",
"42": "text-decoration-line",
"43": "text-indent",
"44": "text-justify",
"45": "text-shadow",
"46": "text-transform",
"47": "visibility",
"48": "white-space",
"49": "word-break",
"50": "word-spacing",
"51": "word-wrap",
"52": "writing-mode",
"53": "align-content",
"54": "align-items",
"55": "align-self",
"56": "animation-delay",
"57": "animation-direction",
"58": "animation-duration",
"59": "animation-fill-mode",
"60": "animation-iteration-count",
"61": "animation-name",
"62": "animation-play-state",
"63": "animation-timing-function",
"64": "appearance",
"65": "aspect-ratio",
"66": "backdrop-filter",
"67": "background-attachment",
"68": "background-clip",
"69": "background-color",
"70": "background-image",
"71": "background-origin",
"72": "background-position-x",
"73": "background-position-y",
"74": "background-repeat",
"75": "background-size",
"76": "border-bottom-color",
"77": "border-bottom-left-radius",
"78": "border-bottom-right-radius",
"79": "border-bottom-style",
"80": "border-bottom-width",
"81": "border-left-color",
"82": "border-left-style",
"83": "border-left-width",
"84": "border-right-color",
"85": "border-right-style",
"86": "border-right-width",
"87": "border-top-color",
"88": "border-top-left-radius",
"89": "border-top-right-radius",
"90": "border-top-style",
"91": "border-top-width",
"92": "bottom",
"93": "box-shadow",
"94": "box-sizing",
"95": "clear",
"96": "clip",
"97": "clip-path",
"98": "column-count",
"99": "column-gap",
"100": "column-span",
"101": "column-width",
"102": "content",
"103": "content-visibility",
"104": "counter-increment",
"105": "counter-reset",
"106": "counter-set",
"107": "cx",
"108": "cy",
"109": "display",
"110": "filter",
"111": "flex-basis",
"112": "flex-direction",
"113": "flex-grow",
"114": "flex-shrink",
"115": "flex-wrap",
"116": "float",
"117": "grid-auto-columns",
"118": "grid-auto-flow",
"119": "grid-auto-rows",
"120": "grid-column-end",
"121": "grid-column-start",
"122": "grid-row-end",
"123": "grid-row-start",
"124": "grid-template-areas",
"125": "grid-template-columns",
"126": "grid-template-rows",
"127": "height",
"128": "inline-size",
"129": "inset-block-end",
"130": "inset-block-start",
"131": "inset-inline-end",
"132": "inset-inline-start",
"133": "justify-content",
"134": "justify-items",
"135": "justify-self",
"136": "left",
"137": "margin-block-end",
"138": "margin-block-start",
"139": "margin-bottom",
"140": "margin-inline-end",
"141": "margin-inline-start",
"142": "margin-left",
"143": "margin-right",
"144": "margin-top",
"145": "mask",
"146": "mask-image",
"147": "mask-type",
"148": "max-height",
"149": "max-inline-size",
"150": "max-width",
"151": "min-height",
"152": "min-inline-size",
"153": "min-width",
"154": "object-fit",
"155": "object-position",
"156": "opacity",
"157": "order",
"158": "outline-color",
"159": "outline-offset",
"160": "outline-style",
"161": "outline-width",
"162": "overflow-x",
"163": "overflow-y",
"164": "padding-block-end",
"165": "padding-block-start",
"166": "padding-bottom",
"167": "padding-inline-end",
"168": "padding-inline-start",
"169": "padding-left",
"170": "padding-right",
"171": "padding-top",
"172": "position",
"173": "r",
"174": "right",
"175": "rotate",
"176": "row-gap",
"177": "rx",
"178": "ry",
"179": "scrollbar-gutter",
"180": "scrollbar-width",
"181": "stop-color",
"182": "stop-opacity",
"183": "table-layout",
"184": "text-decoration-color",
"185": "text-decoration-style",
"186": "text-decoration-thickness",
"187": "text-overflow",
"188": "top",
"189": "transform",
"190": "transform-box",
"191": "transform-origin",
"192": "transition-delay",
"193": "transition-duration",
"194": "transition-property",
"195": "transition-timing-function",
"196": "unicode-bidi",
"197": "user-select",
"198": "vertical-align",
"199": "width",
"200": "x",
"201": "y",
"202": "z-index"
"18": "font-variant-alternates",
"19": "font-variant-caps",
"20": "font-variant-east-asian",
"21": "font-variant-emoji",
"22": "font-variant-ligatures",
"23": "font-variant-numeric",
"24": "font-variant-position",
"25": "font-variation-settings",
"26": "font-weight",
"27": "font-width",
"28": "image-rendering",
"29": "letter-spacing",
"30": "line-height",
"31": "list-style-image",
"32": "list-style-position",
"33": "list-style-type",
"34": "math-depth",
"35": "math-shift",
"36": "math-style",
"37": "pointer-events",
"38": "quotes",
"39": "stroke",
"40": "stroke-linecap",
"41": "stroke-linejoin",
"42": "stroke-miterlimit",
"43": "stroke-opacity",
"44": "stroke-width",
"45": "tab-size",
"46": "text-align",
"47": "text-anchor",
"48": "text-decoration-line",
"49": "text-indent",
"50": "text-justify",
"51": "text-shadow",
"52": "text-transform",
"53": "visibility",
"54": "white-space",
"55": "word-break",
"56": "word-spacing",
"57": "word-wrap",
"58": "writing-mode",
"59": "align-content",
"60": "align-items",
"61": "align-self",
"62": "animation-delay",
"63": "animation-direction",
"64": "animation-duration",
"65": "animation-fill-mode",
"66": "animation-iteration-count",
"67": "animation-name",
"68": "animation-play-state",
"69": "animation-timing-function",
"70": "appearance",
"71": "aspect-ratio",
"72": "backdrop-filter",
"73": "background-attachment",
"74": "background-clip",
"75": "background-color",
"76": "background-image",
"77": "background-origin",
"78": "background-position-x",
"79": "background-position-y",
"80": "background-repeat",
"81": "background-size",
"82": "border-bottom-color",
"83": "border-bottom-left-radius",
"84": "border-bottom-right-radius",
"85": "border-bottom-style",
"86": "border-bottom-width",
"87": "border-left-color",
"88": "border-left-style",
"89": "border-left-width",
"90": "border-right-color",
"91": "border-right-style",
"92": "border-right-width",
"93": "border-top-color",
"94": "border-top-left-radius",
"95": "border-top-right-radius",
"96": "border-top-style",
"97": "border-top-width",
"98": "bottom",
"99": "box-shadow",
"100": "box-sizing",
"101": "clear",
"102": "clip",
"103": "clip-path",
"104": "column-count",
"105": "column-gap",
"106": "column-span",
"107": "column-width",
"108": "content",
"109": "content-visibility",
"110": "counter-increment",
"111": "counter-reset",
"112": "counter-set",
"113": "cx",
"114": "cy",
"115": "display",
"116": "filter",
"117": "flex-basis",
"118": "flex-direction",
"119": "flex-grow",
"120": "flex-shrink",
"121": "flex-wrap",
"122": "float",
"123": "grid-auto-columns",
"124": "grid-auto-flow",
"125": "grid-auto-rows",
"126": "grid-column-end",
"127": "grid-column-start",
"128": "grid-row-end",
"129": "grid-row-start",
"130": "grid-template-areas",
"131": "grid-template-columns",
"132": "grid-template-rows",
"133": "height",
"134": "inline-size",
"135": "inset-block-end",
"136": "inset-block-start",
"137": "inset-inline-end",
"138": "inset-inline-start",
"139": "justify-content",
"140": "justify-items",
"141": "justify-self",
"142": "left",
"143": "margin-block-end",
"144": "margin-block-start",
"145": "margin-bottom",
"146": "margin-inline-end",
"147": "margin-inline-start",
"148": "margin-left",
"149": "margin-right",
"150": "margin-top",
"151": "mask",
"152": "mask-image",
"153": "mask-type",
"154": "max-height",
"155": "max-inline-size",
"156": "max-width",
"157": "min-height",
"158": "min-inline-size",
"159": "min-width",
"160": "object-fit",
"161": "object-position",
"162": "opacity",
"163": "order",
"164": "outline-color",
"165": "outline-offset",
"166": "outline-style",
"167": "outline-width",
"168": "overflow-x",
"169": "overflow-y",
"170": "padding-block-end",
"171": "padding-block-start",
"172": "padding-bottom",
"173": "padding-inline-end",
"174": "padding-inline-start",
"175": "padding-left",
"176": "padding-right",
"177": "padding-top",
"178": "position",
"179": "r",
"180": "right",
"181": "rotate",
"182": "row-gap",
"183": "rx",
"184": "ry",
"185": "scrollbar-gutter",
"186": "scrollbar-width",
"187": "stop-color",
"188": "stop-opacity",
"189": "table-layout",
"190": "text-decoration-color",
"191": "text-decoration-style",
"192": "text-decoration-thickness",
"193": "text-overflow",
"194": "top",
"195": "transform",
"196": "transform-box",
"197": "transform-origin",
"198": "transition-delay",
"199": "transition-duration",
"200": "transition-property",
"201": "transition-timing-function",
"202": "unicode-bidi",
"203": "user-select",
"204": "vertical-align",
"205": "width",
"206": "x",
"207": "y",
"208": "z-index"
}
All properties associated with document.body.style by default:
{}

View file

@ -16,6 +16,13 @@ font-language-override: normal
font-size: 16px
font-style: normal
font-variant: normal
font-variant-alternates: normal
font-variant-caps: normal
font-variant-east-asian: normal
font-variant-emoji: normal
font-variant-ligatures: normal
font-variant-numeric: normal
font-variant-position: normal
font-variation-settings: normal
font-weight: 400
font-width: normal
@ -125,7 +132,7 @@ grid-row-start: auto
grid-template-areas: none
grid-template-columns: auto
grid-template-rows: auto
height: 2159px
height: 2261px
inline-size: auto
inset-block-end: auto
inset-block-start: auto