diff options
author | Sam Atkins <atkinssj@gmail.com> | 2021-08-14 21:05:15 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-18 10:32:32 +0200 |
commit | b64b97ef88ed826ec2e775b170a409e717fe033c (patch) | |
tree | dbc37448b53c07e480c55755f8353da7fefdc4ab /Userland/Libraries/LibWeb/CSS/StyleProperties.cpp | |
parent | ceece1c75e18fdfffb41670a1500b5c333f2f309 (diff) | |
download | serenity-b64b97ef88ed826ec2e775b170a409e717fe033c.zip |
LibWeb: Implement font-fallback
If the font-family property is set to a StyleValueList, we now iterate
through it, looking up each font in turn until one is found.
StyleResolver no longer needs to handle FontFamily specifically, which
is a nice bonus.
Serenity's current dependence on bitmap fonts leads to some weirdness
here - for example, the `if (!found_font)` path can trigger even if a
generic font family like "sans-serif" is used, since our default
sans-serif font might not be available in the desired size or weight.
The `monospace` variable only exists for that reason.
This is not a complete solution, by a long way! Serenity's font support
is still quite basic, so more work needs to be done there before we can
start implementing the spec's font-matching algorithm. But this is still
an improvement. :^)
Diffstat (limited to 'Userland/Libraries/LibWeb/CSS/StyleProperties.cpp')
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleProperties.cpp | 84 |
1 files changed, 59 insertions, 25 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 90d34e9567..4dfce55295 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -94,22 +94,9 @@ Color StyleProperties::color_or_fallback(CSS::PropertyID id, const DOM::Document void StyleProperties::load_font(Layout::Node const& node) const { - auto family_value = string_or_fallback(CSS::PropertyID::FontFamily, "Katica"); auto font_size = property(CSS::PropertyID::FontSize).value_or(IdentifierStyleValue::create(CSS::ValueID::Medium)); auto font_weight = property(CSS::PropertyID::FontWeight).value_or(IdentifierStyleValue::create(CSS::ValueID::Normal)); - auto family_parts = family_value.split(','); - auto family = family_parts[0]; - - auto monospace = false; - - if (family.is_one_of("monospace", "ui-monospace")) { - monospace = true; - family = "Csilla"; - } else if (family.is_one_of("serif", "sans-serif", "cursive", "fantasy", "ui-serif", "ui-sans-serif", "ui-rounded")) { - family = "Katica"; - } - int weight = Gfx::FontWeight::Regular; if (font_weight->is_identifier()) { switch (static_cast<const IdentifierStyleValue&>(*font_weight).id()) { @@ -190,21 +177,68 @@ void StyleProperties::load_font(Layout::Node const& node) const } } - FontSelector font_selector { family, size, weight }; - - auto found_font = FontCache::the().get(font_selector); - if (found_font) { - m_font = found_font; - return; + // FIXME: Implement the full font-matching algorithm: https://www.w3.org/TR/css-fonts-4/#font-matching-algorithm + + // Note: This is modified by the find_font() lambda + FontSelector font_selector; + bool monospace = false; + + auto find_font = [&](String const& family) -> RefPtr<Gfx::Font> { + font_selector = { family, size, weight }; + + if (auto found_font = FontCache::the().get(font_selector)) + return found_font; + + if (auto found_font = Gfx::FontDatabase::the().get(family, size, weight)) + return found_font; + + return {}; + }; + + // FIXME: Replace hard-coded font names with a relevant call to FontDatabase. + // Currently, we cannot request the default font's name, or request it at a specific size and weight. + // So, hard-coded font names it is. + auto find_generic_font = [&](ValueID font_id) -> RefPtr<Gfx::Font> { + switch (font_id) { + case ValueID::Monospace: + case ValueID::UiMonospace: + monospace = true; + return find_font("Csilla"); + case ValueID::Serif: + case ValueID::SansSerif: + case ValueID::Cursive: + case ValueID::Fantasy: + case ValueID::UiSerif: + case ValueID::UiSansSerif: + case ValueID::UiRounded: + return find_font("Katica"); + default: + return {}; + } + }; + + RefPtr<Gfx::Font> found_font {}; + + auto family_value = property(PropertyID::FontFamily).value_or(StringStyleValue::create("Katica")); + if (family_value->is_value_list()) { + auto& family_list = static_cast<StyleValueList const&>(*family_value).values(); + for (auto& family : family_list) { + if (family.is_identifier()) { + found_font = find_generic_font(family.to_identifier()); + } else if (family.is_string()) { + found_font = find_font(family.to_string()); + } + if (found_font) + break; + } + } else if (family_value->is_identifier()) { + found_font = find_generic_font(family_value->to_identifier()); + } else if (family_value->is_string()) { + found_font = find_font(family_value->to_string()); } - Gfx::FontDatabase::the().for_each_font([&](auto& font) { - if (font.family() == family && font.weight() == weight && font.presentation_size() == size) - found_font = font; - }); - if (!found_font) { - dbgln("Font not found: '{}' {} {}", family, size, weight); + dbgln("Font not found: '{}' {} {}", family_value->to_string(), size, weight); found_font = font_fallback(monospace, bold); } |