/src/serenity/Userland/Libraries/LibWeb/CSS/StyleInvalidation.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <LibWeb/CSS/StyleInvalidation.h> |
8 | | #include <LibWeb/CSS/StyleProperties.h> |
9 | | |
10 | | namespace Web::CSS { |
11 | | |
12 | | RequiredInvalidationAfterStyleChange compute_property_invalidation(CSS::PropertyID property_id, RefPtr<CSSStyleValue const> const& old_value, RefPtr<CSSStyleValue const> const& new_value) |
13 | 0 | { |
14 | 0 | RequiredInvalidationAfterStyleChange invalidation; |
15 | |
|
16 | 0 | bool const property_value_changed = (!old_value || !new_value) || *old_value != *new_value; |
17 | 0 | if (!property_value_changed) |
18 | 0 | return invalidation; |
19 | | |
20 | | // NOTE: If the computed CSS display, content, or content-visibility property changes, we have to rebuild the entire layout tree. |
21 | | // In the future, we should figure out ways to rebuild a smaller part of the tree. |
22 | 0 | if (AK::first_is_one_of(property_id, CSS::PropertyID::Display, CSS::PropertyID::Content, CSS::PropertyID::ContentVisibility)) { |
23 | 0 | return RequiredInvalidationAfterStyleChange::full(); |
24 | 0 | } |
25 | | |
26 | | // NOTE: If one of the overflow properties change, we rebuild the entire layout tree. |
27 | | // This ensures that overflow propagation from root/body to viewport happens correctly. |
28 | | // In the future, we can make this invalidation narrower. |
29 | 0 | if (property_id == CSS::PropertyID::OverflowX || property_id == CSS::PropertyID::OverflowY) { |
30 | 0 | return RequiredInvalidationAfterStyleChange::full(); |
31 | 0 | } |
32 | | |
33 | | // OPTIMIZATION: Special handling for CSS `visibility`: |
34 | 0 | if (property_id == CSS::PropertyID::Visibility) { |
35 | | // We don't need to relayout if the visibility changes from visible to hidden or vice versa. Only collapse requires relayout. |
36 | 0 | if ((old_value && old_value->to_keyword() == CSS::Keyword::Collapse) != (new_value && new_value->to_keyword() == CSS::Keyword::Collapse)) |
37 | 0 | invalidation.relayout = true; |
38 | | // Of course, we still have to repaint on any visibility change. |
39 | 0 | invalidation.repaint = true; |
40 | 0 | } else if (CSS::property_affects_layout(property_id)) { |
41 | 0 | invalidation.relayout = true; |
42 | 0 | } |
43 | |
|
44 | 0 | if (property_id == CSS::PropertyID::Opacity && old_value && new_value) { |
45 | | // OPTIMIZATION: An element creates a stacking context when its opacity changes from 1 to less than 1 |
46 | | // and stops to create one when opacity returns to 1. So stacking context tree rebuild is |
47 | | // not required for opacity changes within the range below 1. |
48 | 0 | auto old_value_opacity = CSS::StyleProperties::resolve_opacity_value(*old_value); |
49 | 0 | auto new_value_opacity = CSS::StyleProperties::resolve_opacity_value(*new_value); |
50 | 0 | if (old_value_opacity != new_value_opacity && (old_value_opacity == 1 || new_value_opacity == 1)) { |
51 | 0 | invalidation.rebuild_stacking_context_tree = true; |
52 | 0 | } |
53 | 0 | } else if (CSS::property_affects_stacking_context(property_id)) { |
54 | 0 | invalidation.rebuild_stacking_context_tree = true; |
55 | 0 | } |
56 | 0 | invalidation.repaint = true; |
57 | |
|
58 | 0 | return invalidation; |
59 | 0 | } |
60 | | |
61 | | } |