summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@gmail.com>2021-08-14 21:05:15 +0100
committerAndreas Kling <kling@serenityos.org>2021-08-18 10:32:32 +0200
commitb64b97ef88ed826ec2e775b170a409e717fe033c (patch)
treedbc37448b53c07e480c55755f8353da7fefdc4ab
parentceece1c75e18fdfffb41670a1500b5c333f2f309 (diff)
downloadserenity-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. :^)
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleProperties.cpp84
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleResolver.cpp19
2 files changed, 60 insertions, 43 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);
}
diff --git a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
index 245dfa5aef..6ae55d8bab 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
@@ -442,7 +442,7 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
if (value.is_font()) {
auto& font_shorthand = static_cast<CSS::FontStyleValue const&>(value);
style.set_property(CSS::PropertyID::FontSize, font_shorthand.font_size());
- set_property_expanding_shorthands(style, CSS::PropertyID::FontFamily, *font_shorthand.font_families(), document);
+ style.set_property(CSS::PropertyID::FontFamily, font_shorthand.font_families());
style.set_property(CSS::PropertyID::FontStyle, font_shorthand.font_style());
style.set_property(CSS::PropertyID::FontWeight, font_shorthand.font_weight());
style.set_property(CSS::PropertyID::LineHeight, font_shorthand.line_height());
@@ -451,7 +451,6 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
}
if (value.is_builtin()) {
style.set_property(CSS::PropertyID::FontSize, value);
- // FIXME: Support multiple font-families
style.set_property(CSS::PropertyID::FontFamily, value);
style.set_property(CSS::PropertyID::FontStyle, value);
style.set_property(CSS::PropertyID::FontWeight, value);
@@ -462,22 +461,6 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
return;
}
- if (property_id == CSS::PropertyID::FontFamily) {
- if (value.is_value_list()) {
- auto& values_list = static_cast<StyleValueList const&>(value).values();
- // FIXME: Support multiple font-families
- if (!values_list.is_empty()) {
- style.set_property(CSS::PropertyID::FontFamily, values_list.first());
- }
- return;
- }
- if (value.is_builtin() || value.is_string() || value.is_identifier()) {
- style.set_property(CSS::PropertyID::FontFamily, value);
- return;
- }
- return;
- }
-
if (property_id == CSS::PropertyID::Flex) {
if (value.is_flex()) {
auto& flex = static_cast<CSS::FlexStyleValue const&>(value);