mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
LibWeb: Add basic variable font support
Integrates the new `FontVariationSettings` from LibGfx into LibWeb to enable initial variable font functionality. Currently, only the `wght` (weight) axis is fully supported and tested. This update also introduces support for the CSS `font-variation-settings` property.
This commit is contained in:
parent
489381698f
commit
3829a85fde
Notes:
github-actions[bot]
2025-11-04 20:46:29 +00:00
Author: https://github.com/Norbiros
Commit: 3829a85fde
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6439
Reviewed-by: https://github.com/AtkinsSJ
Reviewed-by: https://github.com/gmta
Reviewed-by: https://github.com/kalenikaliaksandr
Reviewed-by: https://github.com/konradekk
7 changed files with 94 additions and 24 deletions
|
|
@ -229,14 +229,14 @@ bool FontLoader::is_loading() const
|
||||||
return m_fetch_controller && !m_vector_font;
|
return m_fetch_controller && !m_vector_font;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<Gfx::Font const> FontLoader::font_with_point_size(float point_size)
|
RefPtr<Gfx::Font const> FontLoader::font_with_point_size(float point_size, Gfx::FontVariationSettings const& variations)
|
||||||
{
|
{
|
||||||
if (!m_vector_font) {
|
if (!m_vector_font) {
|
||||||
if (!m_fetch_controller)
|
if (!m_fetch_controller)
|
||||||
start_loading_next_url();
|
start_loading_next_url();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return m_vector_font->font(point_size);
|
return m_vector_font->font(point_size, variations);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontLoader::start_loading_next_url()
|
void FontLoader::start_loading_next_url()
|
||||||
|
|
@ -330,18 +330,18 @@ struct StyleComputer::MatchingFontCandidate {
|
||||||
FontFaceKey key;
|
FontFaceKey key;
|
||||||
Variant<FontLoaderList*, Gfx::Typeface const*> loader_or_typeface;
|
Variant<FontLoaderList*, Gfx::Typeface const*> loader_or_typeface;
|
||||||
|
|
||||||
[[nodiscard]] RefPtr<Gfx::FontCascadeList const> font_with_point_size(float point_size) const
|
[[nodiscard]] RefPtr<Gfx::FontCascadeList const> font_with_point_size(float point_size, Gfx::FontVariationSettings const& variations) const
|
||||||
{
|
{
|
||||||
auto font_list = Gfx::FontCascadeList::create();
|
auto font_list = Gfx::FontCascadeList::create();
|
||||||
if (auto* loader_list = loader_or_typeface.get_pointer<FontLoaderList*>(); loader_list) {
|
if (auto* loader_list = loader_or_typeface.get_pointer<FontLoaderList*>(); loader_list) {
|
||||||
for (auto const& loader : **loader_list) {
|
for (auto const& loader : **loader_list) {
|
||||||
if (auto font = loader->font_with_point_size(point_size); font)
|
if (auto font = loader->font_with_point_size(point_size, variations); font)
|
||||||
font_list->add(*font, loader->unicode_ranges());
|
font_list->add(*font, loader->unicode_ranges());
|
||||||
}
|
}
|
||||||
return font_list;
|
return font_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
font_list->add(loader_or_typeface.get<Gfx::Typeface const*>()->font(point_size));
|
font_list->add(loader_or_typeface.get<Gfx::Typeface const*>()->font(point_size, variations));
|
||||||
return font_list;
|
return font_list;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1668,27 +1668,27 @@ Length::FontMetrics StyleComputer::calculate_root_element_font_metrics(ComputedP
|
||||||
return font_metrics;
|
return font_metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<Gfx::FontCascadeList const> StyleComputer::find_matching_font_weight_ascending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, bool inclusive)
|
RefPtr<Gfx::FontCascadeList const> StyleComputer::find_matching_font_weight_ascending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive)
|
||||||
{
|
{
|
||||||
using Fn = AK::Function<bool(MatchingFontCandidate const&)>;
|
using Fn = AK::Function<bool(MatchingFontCandidate const&)>;
|
||||||
auto pred = inclusive ? Fn([&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight >= target_weight; })
|
auto pred = inclusive ? Fn([&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight >= target_weight; })
|
||||||
: Fn([&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight > target_weight; });
|
: Fn([&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight > target_weight; });
|
||||||
auto it = find_if(candidates.begin(), candidates.end(), pred);
|
auto it = find_if(candidates.begin(), candidates.end(), pred);
|
||||||
for (; it != candidates.end(); ++it) {
|
for (; it != candidates.end(); ++it) {
|
||||||
if (auto found_font = it->font_with_point_size(font_size_in_pt))
|
if (auto found_font = it->font_with_point_size(font_size_in_pt, variations))
|
||||||
return found_font;
|
return found_font;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<Gfx::FontCascadeList const> StyleComputer::find_matching_font_weight_descending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, bool inclusive)
|
RefPtr<Gfx::FontCascadeList const> StyleComputer::find_matching_font_weight_descending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive)
|
||||||
{
|
{
|
||||||
using Fn = AK::Function<bool(MatchingFontCandidate const&)>;
|
using Fn = AK::Function<bool(MatchingFontCandidate const&)>;
|
||||||
auto pred = inclusive ? Fn([&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight <= target_weight; })
|
auto pred = inclusive ? Fn([&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight <= target_weight; })
|
||||||
: Fn([&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight < target_weight; });
|
: Fn([&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight < target_weight; });
|
||||||
auto it = find_if(candidates.rbegin(), candidates.rend(), pred);
|
auto it = find_if(candidates.rbegin(), candidates.rend(), pred);
|
||||||
for (; it != candidates.rend(); ++it) {
|
for (; it != candidates.rend(); ++it) {
|
||||||
if (auto found_font = it->font_with_point_size(font_size_in_pt))
|
if (auto found_font = it->font_with_point_size(font_size_in_pt, variations))
|
||||||
return found_font;
|
return found_font;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -1732,34 +1732,38 @@ RefPtr<Gfx::FontCascadeList const> StyleComputer::font_matching_algorithm(FlyStr
|
||||||
// If the desired weight is inclusively between 400 and 500, weights greater than or equal to the target weight
|
// If the desired weight is inclusively between 400 and 500, weights greater than or equal to the target weight
|
||||||
// are checked in ascending order until 500 is hit and checked, followed by weights less than the target weight
|
// are checked in ascending order until 500 is hit and checked, followed by weights less than the target weight
|
||||||
// in descending order, followed by weights greater than 500, until a match is found.
|
// in descending order, followed by weights greater than 500, until a match is found.
|
||||||
|
|
||||||
|
Gfx::FontVariationSettings variations;
|
||||||
|
variations.set_weight(weight);
|
||||||
|
|
||||||
if (weight >= 400 && weight <= 500) {
|
if (weight >= 400 && weight <= 500) {
|
||||||
auto it = find_if(matching_family_fonts.begin(), matching_family_fonts.end(),
|
auto it = find_if(matching_family_fonts.begin(), matching_family_fonts.end(),
|
||||||
[&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight >= weight; });
|
[&](auto const& matching_font_candidate) { return matching_font_candidate.key.weight >= weight; });
|
||||||
for (; it != matching_family_fonts.end() && it->key.weight <= 500; ++it) {
|
for (; it != matching_family_fonts.end() && it->key.weight <= 500; ++it) {
|
||||||
if (auto found_font = it->font_with_point_size(font_size_in_pt))
|
if (auto found_font = it->font_with_point_size(font_size_in_pt, variations))
|
||||||
return found_font;
|
return found_font;
|
||||||
}
|
}
|
||||||
if (auto found_font = find_matching_font_weight_descending(matching_family_fonts, weight, font_size_in_pt, false))
|
if (auto found_font = find_matching_font_weight_descending(matching_family_fonts, weight, font_size_in_pt, variations, false))
|
||||||
return found_font;
|
return found_font;
|
||||||
for (; it != matching_family_fonts.end(); ++it) {
|
for (; it != matching_family_fonts.end(); ++it) {
|
||||||
if (auto found_font = it->font_with_point_size(font_size_in_pt))
|
if (auto found_font = it->font_with_point_size(font_size_in_pt, variations))
|
||||||
return found_font;
|
return found_font;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the desired weight is less than 400, weights less than or equal to the desired weight are checked in descending order
|
// If the desired weight is less than 400, weights less than or equal to the desired weight are checked in descending order
|
||||||
// followed by weights above the desired weight in ascending order until a match is found.
|
// followed by weights above the desired weight in ascending order until a match is found.
|
||||||
if (weight < 400) {
|
if (weight < 400) {
|
||||||
if (auto found_font = find_matching_font_weight_descending(matching_family_fonts, weight, font_size_in_pt, true))
|
if (auto found_font = find_matching_font_weight_descending(matching_family_fonts, weight, font_size_in_pt, variations, true))
|
||||||
return found_font;
|
return found_font;
|
||||||
if (auto found_font = find_matching_font_weight_ascending(matching_family_fonts, weight, font_size_in_pt, false))
|
if (auto found_font = find_matching_font_weight_ascending(matching_family_fonts, weight, font_size_in_pt, variations, false))
|
||||||
return found_font;
|
return found_font;
|
||||||
}
|
}
|
||||||
// If the desired weight is greater than 500, weights greater than or equal to the desired weight are checked in ascending order
|
// If the desired weight is greater than 500, weights greater than or equal to the desired weight are checked in ascending order
|
||||||
// followed by weights below the desired weight in descending order until a match is found.
|
// followed by weights below the desired weight in descending order until a match is found.
|
||||||
if (weight > 500) {
|
if (weight > 500) {
|
||||||
if (auto found_font = find_matching_font_weight_ascending(matching_family_fonts, weight, font_size_in_pt, true))
|
if (auto found_font = find_matching_font_weight_ascending(matching_family_fonts, weight, font_size_in_pt, variations, true))
|
||||||
return found_font;
|
return found_font;
|
||||||
if (auto found_font = find_matching_font_weight_descending(matching_family_fonts, weight, font_size_in_pt, false))
|
if (auto found_font = find_matching_font_weight_descending(matching_family_fonts, weight, font_size_in_pt, variations, false))
|
||||||
return found_font;
|
return found_font;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -1821,7 +1825,7 @@ CSSPixels StyleComputer::relative_size_mapping(RelativeSize relative_size, CSSPi
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<Gfx::FontCascadeList const> StyleComputer::compute_font_for_style_values(StyleValue const& font_family, CSSPixels const& font_size, int slope, double font_weight, Percentage const& font_width) const
|
RefPtr<Gfx::FontCascadeList const> StyleComputer::compute_font_for_style_values(StyleValue const& font_family, CSSPixels const& font_size, int slope, double font_weight, Percentage const& font_width, HashMap<FlyString, NumberOrCalculated> const& font_variation_settings, Length::ResolutionContext const& length_resolution_context) const
|
||||||
{
|
{
|
||||||
// FIXME: We round to int here as that is what is expected by our font infrastructure below
|
// FIXME: We round to int here as that is what is expected by our font infrastructure below
|
||||||
auto width = round_to<int>(font_width.value());
|
auto width = round_to<int>(font_width.value());
|
||||||
|
|
@ -1842,10 +1846,32 @@ RefPtr<Gfx::FontCascadeList const> StyleComputer::compute_font_for_style_values(
|
||||||
auto result = Gfx::FontCascadeList::create();
|
auto result = Gfx::FontCascadeList::create();
|
||||||
if (auto it = m_loaded_fonts.find(key); it != m_loaded_fonts.end()) {
|
if (auto it = m_loaded_fonts.find(key); it != m_loaded_fonts.end()) {
|
||||||
auto const& loaders = it->value;
|
auto const& loaders = it->value;
|
||||||
|
|
||||||
|
Gfx::FontVariationSettings variation;
|
||||||
|
variation.set_weight(font_weight);
|
||||||
|
|
||||||
|
CalculationResolutionContext context {
|
||||||
|
.length_resolution_context = length_resolution_context,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const& [tag_string, value] : font_variation_settings) {
|
||||||
|
auto string_view = tag_string.bytes_as_string_view();
|
||||||
|
if (string_view.length() != 4)
|
||||||
|
continue;
|
||||||
|
auto tag = Gfx::FourCC(string_view.characters_without_null_termination());
|
||||||
|
|
||||||
|
auto resolved_value = value.resolved(context);
|
||||||
|
if (!resolved_value.has_value())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
variation.axes.set(tag, resolved_value.release_value());
|
||||||
|
}
|
||||||
|
|
||||||
for (auto const& loader : loaders) {
|
for (auto const& loader : loaders) {
|
||||||
if (auto found_font = loader->font_with_point_size(font_size_in_pt))
|
if (auto found_font = loader->font_with_point_size(font_size_in_pt, variation))
|
||||||
result->add(*found_font, loader->unicode_ranges());
|
result->add(*found_font, loader->unicode_ranges());
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1984,7 +2010,7 @@ void StyleComputer::compute_font(ComputedProperties& style, Optional<DOM::Abstra
|
||||||
|
|
||||||
auto const& font_family = style.property(CSS::PropertyID::FontFamily);
|
auto const& font_family = style.property(CSS::PropertyID::FontFamily);
|
||||||
|
|
||||||
auto font_list = compute_font_for_style_values(font_family, style.font_size(), style.font_slope(), style.font_weight(), style.font_width());
|
auto font_list = compute_font_for_style_values(font_family, style.font_size(), style.font_slope(), style.font_weight(), style.font_width(), style.font_variation_settings().value_or({}), font_computation_context.length_resolution_context);
|
||||||
VERIFY(font_list);
|
VERIFY(font_list);
|
||||||
VERIFY(!font_list->is_empty());
|
VERIFY(!font_list->is_empty());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ public:
|
||||||
static CSSPixels default_user_font_size();
|
static CSSPixels default_user_font_size();
|
||||||
static CSSPixels absolute_size_mapping(AbsoluteSize, CSSPixels default_font_size);
|
static CSSPixels absolute_size_mapping(AbsoluteSize, CSSPixels default_font_size);
|
||||||
static CSSPixels relative_size_mapping(RelativeSize, CSSPixels inherited_font_size);
|
static CSSPixels relative_size_mapping(RelativeSize, CSSPixels inherited_font_size);
|
||||||
RefPtr<Gfx::FontCascadeList const> compute_font_for_style_values(StyleValue const& font_family, CSSPixels const& font_size, int font_slope, double font_weight, Percentage const& font_width) const;
|
RefPtr<Gfx::FontCascadeList const> compute_font_for_style_values(StyleValue const& font_family, CSSPixels const& font_size, int font_slope, double font_weight, Percentage const& font_width, HashMap<FlyString, NumberOrCalculated> const& font_variation_settings, Length::ResolutionContext const& length_resolution_context) const;
|
||||||
[[nodiscard]] RefPtr<StyleValue const> recascade_font_size_if_needed(DOM::AbstractElement, CascadedProperties&) const;
|
[[nodiscard]] RefPtr<StyleValue const> recascade_font_size_if_needed(DOM::AbstractElement, CascadedProperties&) const;
|
||||||
|
|
||||||
void set_viewport_rect(Badge<DOM::Document>, CSSPixelRect const& viewport_rect) { m_viewport_rect = viewport_rect; }
|
void set_viewport_rect(Badge<DOM::Document>, CSSPixelRect const& viewport_rect) { m_viewport_rect = viewport_rect; }
|
||||||
|
|
@ -238,8 +238,8 @@ private:
|
||||||
LogicalAliasMappingContext compute_logical_alias_mapping_context(DOM::AbstractElement, ComputeStyleMode, MatchingRuleSet const&) const;
|
LogicalAliasMappingContext compute_logical_alias_mapping_context(DOM::AbstractElement, ComputeStyleMode, MatchingRuleSet const&) const;
|
||||||
[[nodiscard]] GC::Ptr<ComputedProperties> compute_style_impl(DOM::AbstractElement, ComputeStyleMode, Optional<bool&> did_change_custom_properties) const;
|
[[nodiscard]] GC::Ptr<ComputedProperties> compute_style_impl(DOM::AbstractElement, ComputeStyleMode, Optional<bool&> did_change_custom_properties) const;
|
||||||
[[nodiscard]] GC::Ref<CascadedProperties> compute_cascaded_values(DOM::AbstractElement, bool did_match_any_pseudo_element_rules, ComputeStyleMode, MatchingRuleSet const&, Optional<LogicalAliasMappingContext>, ReadonlySpan<PropertyID> properties_to_cascade) const;
|
[[nodiscard]] GC::Ref<CascadedProperties> compute_cascaded_values(DOM::AbstractElement, bool did_match_any_pseudo_element_rules, ComputeStyleMode, MatchingRuleSet const&, Optional<LogicalAliasMappingContext>, ReadonlySpan<PropertyID> properties_to_cascade) const;
|
||||||
static RefPtr<Gfx::FontCascadeList const> find_matching_font_weight_ascending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, bool inclusive);
|
static RefPtr<Gfx::FontCascadeList const> find_matching_font_weight_ascending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive);
|
||||||
static RefPtr<Gfx::FontCascadeList const> find_matching_font_weight_descending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, bool inclusive);
|
static RefPtr<Gfx::FontCascadeList const> find_matching_font_weight_descending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive);
|
||||||
RefPtr<Gfx::FontCascadeList const> font_matching_algorithm(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const;
|
RefPtr<Gfx::FontCascadeList const> font_matching_algorithm(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const;
|
||||||
void compute_custom_properties(ComputedProperties&, DOM::AbstractElement) const;
|
void compute_custom_properties(ComputedProperties&, DOM::AbstractElement) const;
|
||||||
void compute_math_depth(ComputedProperties&, Optional<DOM::AbstractElement>) const;
|
void compute_math_depth(ComputedProperties&, Optional<DOM::AbstractElement>) const;
|
||||||
|
|
@ -323,7 +323,7 @@ public:
|
||||||
Vector<Gfx::UnicodeRange> const& unicode_ranges() const { return m_unicode_ranges; }
|
Vector<Gfx::UnicodeRange> const& unicode_ranges() const { return m_unicode_ranges; }
|
||||||
RefPtr<Gfx::Typeface const> vector_font() const { return m_vector_font; }
|
RefPtr<Gfx::Typeface const> vector_font() const { return m_vector_font; }
|
||||||
|
|
||||||
RefPtr<Gfx::Font const> font_with_point_size(float point_size);
|
RefPtr<Gfx::Font const> font_with_point_size(float point_size, Gfx::FontVariationSettings const& variations = {});
|
||||||
void start_loading_next_url();
|
void start_loading_next_url();
|
||||||
|
|
||||||
bool is_loading() const;
|
bool is_loading() const;
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,9 @@ void CanvasTextDrawingStyles<IncludingClass, CanvasType>::set_font(StringView fo
|
||||||
computed_font_size->as_length().length().absolute_length_to_px(),
|
computed_font_size->as_length().length().absolute_length_to_px(),
|
||||||
computed_font_style->as_font_style().to_font_slope(),
|
computed_font_style->as_font_style().to_font_slope(),
|
||||||
computed_font_weight->as_number().number(),
|
computed_font_weight->as_number().number(),
|
||||||
computed_font_width->as_percentage().percentage());
|
computed_font_width->as_percentage().percentage(),
|
||||||
|
{},
|
||||||
|
length_resolution_context);
|
||||||
},
|
},
|
||||||
[](HTML::WorkerGlobalScope*) -> RefPtr<Gfx::FontCascadeList const> {
|
[](HTML::WorkerGlobalScope*) -> RefPtr<Gfx::FontCascadeList const> {
|
||||||
// FIXME: implement computing the font for HTML::WorkerGlobalScope
|
// FIXME: implement computing the font for HTML::WorkerGlobalScope
|
||||||
|
|
|
||||||
BIN
Tests/LibWeb/Screenshot/data/variable-font-example.woff2
Normal file
BIN
Tests/LibWeb/Screenshot/data/variable-font-example.woff2
Normal file
Binary file not shown.
|
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<img src="../images/variable-font-weight-ref.png">
|
||||||
BIN
Tests/LibWeb/Screenshot/images/variable-font-weight-ref.png
Normal file
BIN
Tests/LibWeb/Screenshot/images/variable-font-weight-ref.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
32
Tests/LibWeb/Screenshot/input/variable-font-weight.html
Normal file
32
Tests/LibWeb/Screenshot/input/variable-font-weight.html
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Variable-Font-Weight</title>
|
||||||
|
<link rel="match" href="../expected/variable-font-weight-ref.html" />
|
||||||
|
<meta name="fuzzy" content="maxDifference=0-2;totalPixels=0-4066">
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto Flex';
|
||||||
|
src: url(../data/variable-font-example.woff2) format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Roboto Flex', sans-serif;
|
||||||
|
font-synthesis: none;
|
||||||
|
font-synthesis-weight: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<span style="font-family: sans-serif">Sens serif</span>
|
||||||
|
Character outside <b>all unicode-ranges</b>:
|
||||||
|
|
||||||
|
<h1>Character outside all unicode-ranges:</h1>
|
||||||
|
Character outside all unicode-ranges:
|
||||||
|
|
||||||
|
<div style="font-variation-settings: 'wght' 900, 'opsz' 200;">
|
||||||
|
Hello
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue