StyleInvalidation.cpp 2.9 KB

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