Skip to content

Commit f0b64c5

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 15c61b9 commit f0b64c5

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

@@ -2501,6 +2523,26 @@ WillChange ComputedProperties::will_change() const
25012523
return WillChange::make_auto();
25022524
}
25032525

2526+
ValueComparingNonnullRefPtr<Gfx::FontCascadeList const> ComputedProperties::computed_font_list(FontComputer const& font_computer) const
2527+
{
2528+
if (!m_cached_computed_font_list) {
2529+
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());
2530+
VERIFY(!m_cached_computed_font_list->is_empty());
2531+
}
2532+
2533+
return *m_cached_computed_font_list;
2534+
}
2535+
2536+
ValueComparingNonnullRefPtr<Gfx::Font const> ComputedProperties::first_available_computed_font(FontComputer const& font_computer) const
2537+
{
2538+
if (!m_cached_first_available_computed_font)
2539+
// https://drafts.csswg.org/css-fonts/#first-available-font
2540+
// First font for which the character U+0020 (space) is not excluded by a unicode-range
2541+
const_cast<ComputedProperties*>(this)->m_cached_first_available_computed_font = computed_font_list(font_computer)->font_for_code_point(' ');
2542+
2543+
return *m_cached_first_available_computed_font;
2544+
}
2545+
25042546
CSSPixels ComputedProperties::font_size() const
25052547
{
25062548
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
@@ -226,25 +226,9 @@ class WEB_API ComputedProperties final : public JS::Cell {
226226

227227
WillChange will_change() const;
228228

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

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

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

304294
Optional<CSSPixels> m_line_height;
305295

Libraries/LibWeb/CSS/FontComputer.cpp

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

358-
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
358+
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
359359
{
360360
// FIXME: We round to int here as that is what is expected by our font infrastructure below
361361
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
@@ -1459,7 +1459,7 @@ Length::FontMetrics StyleComputer::calculate_root_element_font_metrics(ComputedP
14591459
{
14601460
auto const& root_value = style.property(CSS::PropertyID::FontSize);
14611461

1462-
auto font_pixel_metrics = style.first_available_computed_font().pixel_metrics();
1462+
auto font_pixel_metrics = style.first_available_computed_font(document().font_computer())->pixel_metrics();
14631463
Length::FontMetrics font_metrics { m_default_font_metrics.font_size, font_pixel_metrics, InitialValues::line_height() };
14641464
font_metrics.font_size = root_value.as_length().length().to_px(viewport_rect(), font_metrics, font_metrics);
14651465
font_metrics.line_height = style.line_height();
@@ -1569,15 +1569,7 @@ void StyleComputer::compute_font(ComputedProperties& style, Optional<DOM::Abstra
15691569
PropertyID::FontVariationSettings,
15701570
compute_font_variation_settings(font_variation_settings_value, font_computation_context));
15711571

1572-
auto const& font_family = style.property(CSS::PropertyID::FontFamily);
1573-
1574-
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());
1575-
VERIFY(font_list);
1576-
VERIFY(!font_list->is_empty());
1577-
1578-
RefPtr<Gfx::Font const> const found_font = font_list->first();
1579-
1580-
style.set_computed_font_list(*font_list);
1572+
RefPtr<Gfx::Font const> const found_font = style.first_available_computed_font(m_document->font_computer());
15811573

15821574
Length::FontMetrics line_height_font_metrics {
15831575
style.font_size(),
@@ -1648,7 +1640,7 @@ void StyleComputer::compute_property_values(ComputedProperties& style, Optional<
16481640
{
16491641
Length::FontMetrics font_metrics {
16501642
style.font_size(),
1651-
style.first_available_computed_font().pixel_metrics(),
1643+
style.first_available_computed_font(document().font_computer())->pixel_metrics(),
16521644
style.line_height()
16531645
};
16541646

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_line_height(computed_style.line_height());

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)