Skip to content

Commit fd1b97e

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 a86e5a4 commit fd1b97e

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

@@ -2517,6 +2539,26 @@ WillChange ComputedProperties::will_change() const
25172539
return WillChange::make_auto();
25182540
}
25192541

2542+
ValueComparingNonnullRefPtr<Gfx::FontCascadeList const> ComputedProperties::computed_font_list(FontComputer const& font_computer) const
2543+
{
2544+
if (!m_cached_computed_font_list) {
2545+
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());
2546+
VERIFY(!m_cached_computed_font_list->is_empty());
2547+
}
2548+
2549+
return *m_cached_computed_font_list;
2550+
}
2551+
2552+
ValueComparingNonnullRefPtr<Gfx::Font const> ComputedProperties::first_available_computed_font(FontComputer const& font_computer) const
2553+
{
2554+
if (!m_cached_first_available_computed_font)
2555+
// https://drafts.csswg.org/css-fonts/#first-available-font
2556+
// First font for which the character U+0020 (space) is not excluded by a unicode-range
2557+
const_cast<ComputedProperties*>(this)->m_cached_first_available_computed_font = computed_font_list(font_computer)->font_for_code_point(' ');
2558+
2559+
return *m_cached_first_available_computed_font;
2560+
}
2561+
25202562
CSSPixels ComputedProperties::font_size() const
25212563
{
25222564
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
@@ -228,25 +228,9 @@ class WEB_API ComputedProperties final : public JS::Cell {
228228

229229
WillChange will_change() const;
230230

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

251235
[[nodiscard]] CSSPixels line_height() const;
252236
[[nodiscard]] CSSPixels font_size() const;
@@ -300,8 +284,14 @@ class WEB_API ComputedProperties final : public JS::Cell {
300284
Display m_display_before_box_type_transformation { InitialValues::display() };
301285

302286
int m_math_depth { InitialValues::math_depth() };
303-
RefPtr<Gfx::FontCascadeList const> m_font_list;
304-
RefPtr<Gfx::Font const> m_first_available_computed_font;
287+
288+
RefPtr<Gfx::FontCascadeList const> m_cached_computed_font_list;
289+
RefPtr<Gfx::Font const> m_cached_first_available_computed_font;
290+
void clear_computed_font_list_cache()
291+
{
292+
m_cached_computed_font_list = nullptr;
293+
m_cached_first_available_computed_font = nullptr;
294+
}
305295

306296
Optional<CSSPixels> m_line_height;
307297

Libraries/LibWeb/CSS/FontComputer.cpp

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

355-
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
355+
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
356356
{
357357
// FIXME: We round to int here as that is what is expected by our font infrastructure below
358358
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
@@ -683,7 +683,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
683683

684684
Length::FontMetrics font_metrics {
685685
computed_properties.font_size(),
686-
computed_properties.first_available_computed_font().pixel_metrics(),
686+
computed_properties.first_available_computed_font(document().font_computer())->pixel_metrics(),
687687
computed_properties.line_height()
688688
};
689689

@@ -797,7 +797,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
797797
.viewport_rect = viewport_rect(),
798798
.font_metrics = {
799799
computed_properties.font_size(),
800-
computed_properties.first_available_computed_font().pixel_metrics(),
800+
computed_properties.first_available_computed_font(document().font_computer())->pixel_metrics(),
801801
inheritance_parent_has_computed_properties ? inheritance_parent->computed_properties()->line_height() : InitialValues::line_height() },
802802
.root_font_metrics = m_root_element_font_metrics },
803803
.abstract_element = abstract_element
@@ -1389,7 +1389,7 @@ Length::FontMetrics StyleComputer::calculate_root_element_font_metrics(ComputedP
13891389
{
13901390
auto const& root_value = style.property(CSS::PropertyID::FontSize);
13911391

1392-
auto font_pixel_metrics = style.first_available_computed_font().pixel_metrics();
1392+
auto font_pixel_metrics = style.first_available_computed_font(document().font_computer())->pixel_metrics();
13931393
Length::FontMetrics font_metrics { m_default_font_metrics.font_size, font_pixel_metrics, InitialValues::line_height() };
13941394
font_metrics.font_size = root_value.as_length().length().to_px(viewport_rect(), font_metrics, font_metrics);
13951395
font_metrics.line_height = style.line_height();
@@ -1499,15 +1499,7 @@ void StyleComputer::compute_font(ComputedProperties& style, Optional<DOM::Abstra
14991499
PropertyID::FontVariationSettings,
15001500
compute_font_variation_settings(font_variation_settings_value, font_computation_context));
15011501

1502-
auto const& font_family = style.property(CSS::PropertyID::FontFamily);
1503-
1504-
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());
1505-
VERIFY(font_list);
1506-
VERIFY(!font_list->is_empty());
1507-
1508-
RefPtr<Gfx::Font const> const found_font = font_list->first();
1509-
1510-
style.set_computed_font_list(*font_list);
1502+
RefPtr<Gfx::Font const> const found_font = style.first_available_computed_font(m_document->font_computer());
15111503

15121504
Length::FontMetrics line_height_font_metrics {
15131505
style.font_size(),
@@ -1578,7 +1570,7 @@ void StyleComputer::compute_property_values(ComputedProperties& style, Optional<
15781570
{
15791571
Length::FontMetrics font_metrics {
15801572
style.font_size(),
1581-
style.first_available_computed_font().pixel_metrics(),
1573+
style.first_available_computed_font(document().font_computer())->pixel_metrics(),
15821574
style.line_height()
15831575
};
15841576

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
@@ -397,7 +397,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
397397
// NOTE: We have to be careful that font-related properties get set in the right order.
398398
// m_font is used by Length::to_px() when resolving sizes against this layout node.
399399
// That's why it has to be set before everything else.
400-
computed_values.set_font_list(computed_style.computed_font_list());
400+
computed_values.set_font_list(computed_style.computed_font_list(document().font_computer()));
401401
computed_values.set_font_size(computed_style.font_size());
402402
computed_values.set_font_weight(computed_style.font_weight());
403403
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)