Skip to content

Commit 79e61b1

Browse files
committed
LibWeb: Account for animated values when computing font
Computing the font for an element in `compute_font` is premature since we are yet to apply animated properties - instead we should compute the value on the fly (with a cache to avoid unnecessary work) to ensure we are respecting the latest values
1 parent 52c6092 commit 79e61b1

File tree

12 files changed

+78
-43
lines changed

12 files changed

+78
-43
lines changed

Libraries/LibWeb/CSS/ComputedProperties.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <LibGC/CellAllocator.h>
1212
#include <LibWeb/CSS/Clip.h>
1313
#include <LibWeb/CSS/ComputedProperties.h>
14+
#include <LibWeb/CSS/FontComputer.h>
1415
#include <LibWeb/CSS/StyleValues/ColorSchemeStyleValue.h>
1516
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
1617
#include <LibWeb/CSS/StyleValues/CounterDefinitionsStyleValue.h>
@@ -47,6 +48,21 @@ namespace Web::CSS {
4748

4849
GC_DEFINE_ALLOCATOR(ComputedProperties);
4950

51+
static HashTable<PropertyID> font_affecting_properties()
52+
{
53+
static HashTable<PropertyID> font_affecting_properties;
54+
if (font_affecting_properties.is_empty()) {
55+
font_affecting_properties.set(PropertyID::FontFamily);
56+
font_affecting_properties.set(PropertyID::FontSize);
57+
font_affecting_properties.set(PropertyID::FontStyle);
58+
font_affecting_properties.set(PropertyID::FontWeight);
59+
font_affecting_properties.set(PropertyID::FontWidth);
60+
font_affecting_properties.set(PropertyID::FontVariationSettings);
61+
}
62+
63+
return font_affecting_properties;
64+
}
65+
5066
ComputedProperties::ComputedProperties() = default;
5167

5268
ComputedProperties::~ComputedProperties() = default;
@@ -128,6 +144,9 @@ void ComputedProperties::set_property_without_modifying_flags(PropertyID id, Non
128144
VERIFY(id >= first_longhand_property_id && id <= last_longhand_property_id);
129145

130146
m_property_values[to_underlying(id) - to_underlying(first_longhand_property_id)] = move(value);
147+
148+
if (font_affecting_properties().contains(id))
149+
clear_computed_font_list_cache();
131150
}
132151

133152
void ComputedProperties::revert_property(PropertyID id, ComputedProperties const& style_for_revert)
@@ -153,6 +172,9 @@ void ComputedProperties::set_animated_property(PropertyID id, NonnullRefPtr<Styl
153172
{
154173
m_animated_property_values.set(id, move(value));
155174
set_animated_property_inherited(id, inherited);
175+
176+
if (font_affecting_properties().contains(id))
177+
clear_computed_font_list_cache();
156178
}
157179

158180
void ComputedProperties::remove_animated_property(PropertyID id)
@@ -175,7 +197,7 @@ StyleValue const& ComputedProperties::property(PropertyID property_id, WithAnima
175197
return *animated_value.value();
176198
}
177199

178-
// By the time we call this method, all properties have values assigned.
200+
// By the time we call this method, the property should have been assigned
179201
return *m_property_values[to_underlying(property_id) - to_underlying(first_longhand_property_id)];
180202
}
181203

@@ -2232,6 +2254,26 @@ WillChange ComputedProperties::will_change() const
22322254
return WillChange::make_auto();
22332255
}
22342256

2257+
ValueComparingNonnullRefPtr<Gfx::FontCascadeList const> ComputedProperties::computed_font_list(FontComputer const& font_computer) const
2258+
{
2259+
if (!m_cached_computed_font_list) {
2260+
const_cast<ComputedProperties*>(this)->m_cached_computed_font_list = font_computer.compute_font_for_style_values(property(PropertyID::FontFamily), font_size(), font_slope(), font_weight(), font_width(), font_variation_settings());
2261+
VERIFY(!m_cached_computed_font_list->is_empty());
2262+
}
2263+
2264+
return *m_cached_computed_font_list;
2265+
}
2266+
2267+
ValueComparingNonnullRefPtr<Gfx::Font const> ComputedProperties::first_available_computed_font(FontComputer const& font_computer) const
2268+
{
2269+
if (!m_cached_first_available_computed_font)
2270+
// https://drafts.csswg.org/css-fonts/#first-available-font
2271+
// First font for which the character U+0020 (space) is not excluded by a unicode-range
2272+
const_cast<ComputedProperties*>(this)->m_cached_first_available_computed_font = computed_font_list(font_computer)->font_for_code_point(' ');
2273+
2274+
return *m_cached_first_available_computed_font;
2275+
}
2276+
22352277
CSSPixels ComputedProperties::font_size() const
22362278
{
22372279
return property(PropertyID::FontSize).as_length().length().absolute_length_to_px();

Libraries/LibWeb/CSS/ComputedProperties.h

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -225,25 +225,9 @@ class WEB_API ComputedProperties final : public JS::Cell {
225225

226226
WillChange will_change() const;
227227

228-
Gfx::FontCascadeList const& computed_font_list() const
229-
{
230-
VERIFY(m_font_list);
231-
return *m_font_list;
232-
}
233-
234-
Gfx::Font const& first_available_computed_font() const
235-
{
236-
VERIFY(m_first_available_computed_font);
237-
return *m_first_available_computed_font;
238-
}
239-
240-
void set_computed_font_list(NonnullRefPtr<Gfx::FontCascadeList const> font_list)
241-
{
242-
m_font_list = move(font_list);
243-
// https://drafts.csswg.org/css-fonts/#first-available-font
244-
// First font for which the character U+0020 (space) is not excluded by a unicode-range
245-
m_first_available_computed_font = m_font_list->font_for_code_point(' ');
246-
}
228+
ValueComparingRefPtr<Gfx::FontCascadeList const> cached_computed_font_list() const { return m_cached_computed_font_list; }
229+
ValueComparingNonnullRefPtr<Gfx::FontCascadeList const> computed_font_list(FontComputer const&) const;
230+
ValueComparingNonnullRefPtr<Gfx::Font const> first_available_computed_font(FontComputer const&) const;
247231

248232
[[nodiscard]] CSSPixels line_height() const;
249233
[[nodiscard]] CSSPixels font_size() const;
@@ -297,8 +281,14 @@ class WEB_API ComputedProperties final : public JS::Cell {
297281
Display m_display_before_box_type_transformation { InitialValues::display() };
298282

299283
int m_math_depth { InitialValues::math_depth() };
300-
RefPtr<Gfx::FontCascadeList const> m_font_list;
301-
RefPtr<Gfx::Font const> m_first_available_computed_font;
284+
285+
RefPtr<Gfx::FontCascadeList const> m_cached_computed_font_list;
286+
RefPtr<Gfx::Font const> m_cached_first_available_computed_font;
287+
void clear_computed_font_list_cache()
288+
{
289+
m_cached_computed_font_list = nullptr;
290+
m_cached_first_available_computed_font = nullptr;
291+
}
302292

303293
Optional<CSSPixels> m_line_height;
304294

Libraries/LibWeb/CSS/FontComputer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ RefPtr<Gfx::FontCascadeList const> FontComputer::font_matching_algorithm_impl(Fl
354354
return {};
355355
}
356356

357-
RefPtr<Gfx::FontCascadeList const> FontComputer::compute_font_for_style_values(StyleValue const& font_family, CSSPixels const& font_size, int slope, double font_weight, Percentage const& font_width, HashMap<FlyString, double> const& font_variation_settings) const
357+
NonnullRefPtr<Gfx::FontCascadeList const> FontComputer::compute_font_for_style_values(StyleValue const& font_family, CSSPixels const& font_size, int slope, double font_weight, Percentage const& font_width, HashMap<FlyString, double> const& font_variation_settings) const
358358
{
359359
// FIXME: We round to int here as that is what is expected by our font infrastructure below
360360
auto width = round_to<int>(font_width.value());

Libraries/LibWeb/CSS/FontComputer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class WEB_API FontComputer final : public GC::Cell {
100100
void load_fonts_from_sheet(CSSStyleSheet&);
101101
void unload_fonts_from_sheet(CSSStyleSheet&);
102102

103-
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, double> const& font_variation_settings) const;
103+
NonnullRefPtr<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, double> const& font_variation_settings) const;
104104

105105
size_t number_of_css_font_faces_with_loading_in_progress() const;
106106

Libraries/LibWeb/CSS/Length.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ Length::ResolutionContext Length::ResolutionContext::for_element(DOM::AbstractEl
132132

133133
return Length::ResolutionContext {
134134
.viewport_rect = element.element().navigable()->viewport_rect(),
135-
.font_metrics = { element.computed_properties()->font_size(), element.computed_properties()->first_available_computed_font().pixel_metrics(), element.computed_properties()->line_height() },
136-
.root_font_metrics = { root_element->computed_properties()->font_size(), root_element->computed_properties()->first_available_computed_font().pixel_metrics(), element.computed_properties()->line_height() }
135+
.font_metrics = { element.computed_properties()->font_size(), element.computed_properties()->first_available_computed_font(element.document().font_computer())->pixel_metrics(), element.computed_properties()->line_height() },
136+
.root_font_metrics = { root_element->computed_properties()->font_size(), root_element->computed_properties()->first_available_computed_font(element.document().font_computer())->pixel_metrics(), element.computed_properties()->line_height() }
137137
};
138138
}
139139

Libraries/LibWeb/CSS/StyleComputer.cpp

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
754754

755755
Length::FontMetrics font_metrics {
756756
computed_properties.font_size(),
757-
computed_properties.first_available_computed_font().pixel_metrics(),
757+
computed_properties.first_available_computed_font(document().font_computer())->pixel_metrics(),
758758
computed_properties.line_height()
759759
};
760760

@@ -868,7 +868,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
868868
.viewport_rect = viewport_rect(),
869869
.font_metrics = {
870870
computed_properties.font_size(),
871-
computed_properties.first_available_computed_font().pixel_metrics(),
871+
computed_properties.first_available_computed_font(document().font_computer())->pixel_metrics(),
872872
inheritance_parent_has_computed_properties ? inheritance_parent->computed_properties()->line_height() : InitialValues::line_height() },
873873
.root_font_metrics = m_root_element_font_metrics },
874874
.abstract_element = abstract_element
@@ -1451,7 +1451,7 @@ Length::FontMetrics StyleComputer::calculate_root_element_font_metrics(ComputedP
14511451
{
14521452
auto const& root_value = style.property(CSS::PropertyID::FontSize);
14531453

1454-
auto font_pixel_metrics = style.first_available_computed_font().pixel_metrics();
1454+
auto font_pixel_metrics = style.first_available_computed_font(document().font_computer())->pixel_metrics();
14551455
Length::FontMetrics font_metrics { m_default_font_metrics.font_size, font_pixel_metrics, InitialValues::line_height() };
14561456
font_metrics.font_size = root_value.as_length().length().to_px(viewport_rect(), font_metrics, font_metrics);
14571457
font_metrics.line_height = style.line_height();
@@ -1561,15 +1561,7 @@ void StyleComputer::compute_font(ComputedProperties& style, Optional<DOM::Abstra
15611561
PropertyID::FontVariationSettings,
15621562
compute_font_variation_settings(font_variation_settings_value, font_computation_context));
15631563

1564-
auto const& font_family = style.property(CSS::PropertyID::FontFamily);
1565-
1566-
auto font_list = document().font_computer().compute_font_for_style_values(font_family, style.font_size(), style.font_slope(), style.font_weight(), style.font_width(), style.font_variation_settings());
1567-
VERIFY(font_list);
1568-
VERIFY(!font_list->is_empty());
1569-
1570-
RefPtr<Gfx::Font const> const found_font = font_list->first();
1571-
1572-
style.set_computed_font_list(*font_list);
1564+
RefPtr<Gfx::Font const> const found_font = style.first_available_computed_font(m_document->font_computer());
15731565

15741566
Length::FontMetrics line_height_font_metrics {
15751567
style.font_size(),
@@ -1640,7 +1632,7 @@ void StyleComputer::compute_property_values(ComputedProperties& style, Optional<
16401632
{
16411633
Length::FontMetrics font_metrics {
16421634
style.font_size(),
1643-
style.first_available_computed_font().pixel_metrics(),
1635+
style.first_available_computed_font(document().font_computer())->pixel_metrics(),
16441636
style.line_height()
16451637
};
16461638

Libraries/LibWeb/DOM/Element.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ static CSS::RequiredInvalidationAfterStyleChange compute_required_invalidation(C
697697
{
698698
CSS::RequiredInvalidationAfterStyleChange invalidation;
699699

700-
if (!old_style.computed_font_list().equals(new_style.computed_font_list()))
700+
if (old_style.cached_computed_font_list() != new_style.cached_computed_font_list())
701701
invalidation.relayout = true;
702702

703703
for (auto i = to_underlying(CSS::first_longhand_property_id); i <= to_underlying(CSS::last_longhand_property_id); ++i) {

Libraries/LibWeb/HTML/HTMLInputElement.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ void HTMLInputElement::adjust_computed_style(CSS::ComputedProperties& style)
149149
// NOTE: Other browsers apply a minimum height of a single line's line-height to single-line input elements.
150150
if (is_single_line() && style.property(CSS::PropertyID::Height).has_auto()) {
151151
auto current_line_height = style.line_height().to_double();
152-
auto minimum_line_height = style.first_available_computed_font().pixel_size() * CSS::ComputedProperties::normal_line_height_scale;
152+
auto minimum_line_height = style.first_available_computed_font(document().font_computer())->pixel_size() * CSS::ComputedProperties::normal_line_height_scale;
153153

154154
// FIXME: Instead of overriding line-height, we should set height here instead.
155155
if (current_line_height < minimum_line_height)

Libraries/LibWeb/Layout/Node.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
379379
// NOTE: We have to be careful that font-related properties get set in the right order.
380380
// m_font is used by Length::to_px() when resolving sizes against this layout node.
381381
// That's why it has to be set before everything else.
382-
computed_values.set_font_list(computed_style.computed_font_list());
382+
computed_values.set_font_list(computed_style.computed_font_list(document().font_computer()));
383383
computed_values.set_font_size(computed_style.font_size());
384384
computed_values.set_font_weight(computed_style.font_weight());
385385
computed_values.set_font_kerning(computed_style.font_kerning());

Services/WebContent/ConnectionFromClient.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ void ConnectionFromClient::inspect_dom_node(u64 page_id, WebView::DOMNodePropert
540540
auto serialize_used_fonts = [&]() {
541541
JsonArray serialized;
542542

543-
properties->computed_font_list().for_each_font_entry([&](Gfx::FontCascadeList::Entry const& entry) {
543+
properties->computed_font_list(node->document().font_computer())->for_each_font_entry([&](Gfx::FontCascadeList::Entry const& entry) {
544544
auto const& font = *entry.font;
545545

546546
JsonObject font_object;

0 commit comments

Comments
 (0)