From 87072d8badcb460a460fb71b08a258e09c25b6ca Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Tue, 16 Nov 2021 16:11:05 +0000 Subject: [PATCH] [inert] Force 'pointer-events: none' on inert nodes at used-value time The CSSWG resolved that inert nodes should behave as if they had 'pointer-events: none', but without changing the computed style. https://github.com/w3c/csswg-drafts/issues/6685#issuecomment-930305697 This is done by adding a public ComputedStyle::UsedPointerEvents() that returns EPointerEvents::kNone for inert, and privatizing the existing ComputedStyle::PointerEvents() just for friend classes. Note that computed_style_fields.py needs to be tweaked, otherwise the automatically generated PropagateIndependentInheritedProperties() would still try to call ResetPointerEventsIsInherited(), which is no longer defined. Now it needs to be ResetPointerEventsIsInheritedInternal(). After this change, it will be possible to remove the hit-testing retargeting for inert. Bug: 692360 TEST=external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-inert.tentative.html TEST=external/wpt/inert/inert-computed-style.html Change-Id: I720908d3e1c47d7cd13b9fe9e1110e44ff70f56b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3281968 Reviewed-by: Anders Hartvoll Ruud Reviewed-by: Rune Lillesveen Commit-Queue: Oriol Brufau Cr-Commit-Position: refs/heads/main@{#942180} NOKEYCHECK=True GitOrigin-RevId: 6aadd45a00e1d6512dd17c3a2d31f5d89647c97e --- .../scripts/core/style/computed_style_fields.py | 5 ++++- blink/renderer/core/css/css_properties.json5 | 1 + blink/renderer/core/layout/layout_object.h | 2 +- .../renderer/core/layout/svg/layout_svg_container.cc | 2 +- blink/renderer/core/layout/svg/layout_svg_image.cc | 2 +- blink/renderer/core/layout/svg/layout_svg_shape.cc | 2 +- blink/renderer/core/layout/svg/layout_svg_text.cc | 2 +- .../core/layout/svg/line/svg_inline_text_box.cc | 2 +- .../core/paint/ng/ng_box_fragment_painter.cc | 8 ++++---- blink/renderer/core/paint/paint_layer.cc | 4 ++-- blink/renderer/core/style/computed_style.h | 12 +++++++++++- blink/renderer/core/svg/svg_svg_element.cc | 2 +- .../dialog-inert.tentative-expected.txt | 4 ---- .../wpt/inert/inert-computed-style-expected.txt | 4 ---- 14 files changed, 29 insertions(+), 23 deletions(-) delete mode 100644 blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-inert.tentative-expected.txt delete mode 100644 blink/web_tests/external/wpt/inert/inert-computed-style-expected.txt diff --git a/blink/renderer/build/scripts/core/style/computed_style_fields.py b/blink/renderer/build/scripts/core/style/computed_style_fields.py index 3f2199b4954..c92a1528a63 100644 --- a/blink/renderer/build/scripts/core/style/computed_style_fields.py +++ b/blink/renderer/build/scripts/core/style/computed_style_fields.py @@ -185,7 +185,10 @@ def __init__(self, field_role, name_for_methods, property_name, type_name, assert self.is_inherited or not self.is_independent, \ 'Only inherited fields can be independent' + suffix = ['is', 'inherited'] + if 'getter' in self.computed_style_custom_functions: + suffix.append('internal') self.is_inherited_method_name = name_source.to_function_name( - suffix=['is', 'inherited']) + suffix=suffix) assert len(kwargs) == 0, \ 'Unexpected arguments provided to Field: ' + str(kwargs) diff --git a/blink/renderer/core/css/css_properties.json5 b/blink/renderer/core/css/css_properties.json5 index 75021317018..ad9b53ac61b 100644 --- a/blink/renderer/core/css/css_properties.json5 +++ b/blink/renderer/core/css/css_properties.json5 @@ -3436,6 +3436,7 @@ { name: "pointer-events", property_methods: ["CSSValueFromComputedStyleInternal"], + computed_style_custom_functions: ["getter"], independent: true, inherited: true, field_template: "keyword", diff --git a/blink/renderer/core/layout/layout_object.h b/blink/renderer/core/layout/layout_object.h index ce41c0fe4f2..013ff553b85 100644 --- a/blink/renderer/core/layout/layout_object.h +++ b/blink/renderer/core/layout/layout_object.h @@ -2849,7 +2849,7 @@ class CORE_EXPORT LayoutObject : public GarbageCollected, NOT_DESTROYED(); return StyleRef().Visibility() == EVisibility::kVisible && (request.IgnorePointerEventsNone() || - StyleRef().PointerEvents() != EPointerEvents::kNone); + StyleRef().UsedPointerEvents() != EPointerEvents::kNone); } bool VisibleToHitTesting() const { diff --git a/blink/renderer/core/layout/svg/layout_svg_container.cc b/blink/renderer/core/layout/svg/layout_svg_container.cc index c7ce425275c..d4ba15a5da4 100644 --- a/blink/renderer/core/layout/svg/layout_svg_container.cc +++ b/blink/renderer/core/layout/svg/layout_svg_container.cc @@ -214,7 +214,7 @@ bool LayoutSVGContainer::NodeAtPoint(HitTestResult& result, // pointer-events: bounding-box makes it possible for containers to be direct // targets. - if (StyleRef().PointerEvents() == EPointerEvents::kBoundingBox) { + if (StyleRef().UsedPointerEvents() == EPointerEvents::kBoundingBox) { // Check for a valid bounding box because it will be invalid for empty // containers. if (IsObjectBoundingBoxValid() && diff --git a/blink/renderer/core/layout/svg/layout_svg_image.cc b/blink/renderer/core/layout/svg/layout_svg_image.cc index 204932d117d..63f1c980cc9 100644 --- a/blink/renderer/core/layout/svg/layout_svg_image.cc +++ b/blink/renderer/core/layout/svg/layout_svg_image.cc @@ -218,7 +218,7 @@ bool LayoutSVGImage::NodeAtPoint(HitTestResult& result, const ComputedStyle& style = StyleRef(); PointerEventsHitRules hit_rules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, result.GetHitTestRequest(), - style.PointerEvents()); + style.UsedPointerEvents()); if (hit_rules.require_visible && style.Visibility() != EVisibility::kVisible) return false; diff --git a/blink/renderer/core/layout/svg/layout_svg_shape.cc b/blink/renderer/core/layout/svg/layout_svg_shape.cc index 80382679d15..1f62f9df64b 100644 --- a/blink/renderer/core/layout/svg/layout_svg_shape.cc +++ b/blink/renderer/core/layout/svg/layout_svg_shape.cc @@ -402,7 +402,7 @@ bool LayoutSVGShape::NodeAtPoint(HitTestResult& result, const ComputedStyle& style = StyleRef(); const PointerEventsHitRules hit_rules( PointerEventsHitRules::SVG_GEOMETRY_HITTESTING, - result.GetHitTestRequest(), style.PointerEvents()); + result.GetHitTestRequest(), style.UsedPointerEvents()); if (hit_rules.require_visible && style.Visibility() != EVisibility::kVisible) return false; diff --git a/blink/renderer/core/layout/svg/layout_svg_text.cc b/blink/renderer/core/layout/svg/layout_svg_text.cc index 3b448a7126b..a523ed5824d 100644 --- a/blink/renderer/core/layout/svg/layout_svg_text.cc +++ b/blink/renderer/core/layout/svg/layout_svg_text.cc @@ -355,7 +355,7 @@ bool LayoutSVGText::NodeAtPoint(HitTestResult& result, return true; // Consider the bounding box if requested. - if (StyleRef().PointerEvents() == EPointerEvents::kBoundingBox) { + if (StyleRef().UsedPointerEvents() == EPointerEvents::kBoundingBox) { if (IsObjectBoundingBoxValid() && local_location->Intersects(ObjectBoundingBox())) { UpdateHitTestResult(result, PhysicalOffset::FromFloatPointRound( diff --git a/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc b/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc index e47edf12923..e3db41fa1d7 100644 --- a/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc +++ b/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc @@ -309,7 +309,7 @@ bool SVGInlineTextBox::NodeAtPoint(HitTestResult& result, const ComputedStyle& style = line_layout_item.StyleRef(); PointerEventsHitRules hit_rules(PointerEventsHitRules::SVG_TEXT_HITTESTING, result.GetHitTestRequest(), - style.PointerEvents()); + style.UsedPointerEvents()); if (hit_rules.require_visible && style.Visibility() != EVisibility::kVisible) return false; if (hit_rules.can_hit_bounding_box || diff --git a/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index c120e860143..40d02bcf40d 100644 --- a/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc @@ -105,7 +105,7 @@ inline bool IsVisibleToPaint(const NGFragmentItem& item, inline bool IsVisibleToHitTest(const ComputedStyle& style, const HitTestRequest& request) { return request.IgnorePointerEventsNone() || - style.PointerEvents() != EPointerEvents::kNone; + style.UsedPointerEvents() != EPointerEvents::kNone; } inline bool IsVisibleToHitTest(const NGFragmentItem& item, @@ -117,7 +117,7 @@ inline bool IsVisibleToHitTest(const NGFragmentItem& item, if (item.IsHiddenForPaint()) return false; PointerEventsHitRules hit_rules(PointerEventsHitRules::SVG_TEXT_HITTESTING, - request, style.PointerEvents()); + request, style.UsedPointerEvents()); if (hit_rules.require_visible && style.Visibility() != EVisibility::kVisible) return false; if (hit_rules.can_hit_bounding_box || @@ -1930,7 +1930,7 @@ bool NGBoxFragmentPainter::NodeAtPoint(const HitTestContext& hit_test, hit_test_self = false; } else if (fragment.IsSvgText()) { pointer_events_bounding_box = - fragment.Style().PointerEvents() == EPointerEvents::kBoundingBox; + fragment.Style().UsedPointerEvents() == EPointerEvents::kBoundingBox; hit_test_self = pointer_events_bounding_box; } } @@ -2271,7 +2271,7 @@ bool NGBoxFragmentPainter::HitTestChildBoxItem( } if (cursor.ContainerFragment().IsSvgText() && - item.Style().PointerEvents() != EPointerEvents::kBoundingBox) + item.Style().UsedPointerEvents() != EPointerEvents::kBoundingBox) return false; // Now hit test ourselves. diff --git a/blink/renderer/core/paint/paint_layer.cc b/blink/renderer/core/paint/paint_layer.cc index fefafa968e1..086b9325eef 100644 --- a/blink/renderer/core/paint/paint_layer.cc +++ b/blink/renderer/core/paint/paint_layer.cc @@ -3457,8 +3457,8 @@ bool PaintLayer::AttemptDirectCompositingUpdate( // Changes in pointer-events affect hit test visibility of the scrollable // area and its |m_scrollsOverflow| value which determines if the layer // requires composited scrolling or not. - if (scrollable_area_ && - layout_object_->StyleRef().PointerEvents() != old_style->PointerEvents()) + if (scrollable_area_ && layout_object_->StyleRef().UsedPointerEvents() != + old_style->UsedPointerEvents()) return false; UpdateTransform(old_style, GetLayoutObject().StyleRef()); diff --git a/blink/renderer/core/style/computed_style.h b/blink/renderer/core/style/computed_style.h index 9b4199108c6..507543cdaf3 100644 --- a/blink/renderer/core/style/computed_style.h +++ b/blink/renderer/core/style/computed_style.h @@ -135,6 +135,7 @@ class InternalVisitedTextFillColor; class InternalVisitedTextStrokeColor; class LightingColor; class OutlineColor; +class PointerEvents; class Position; class Resize; class StopColor; @@ -248,6 +249,7 @@ class ComputedStyle : public ComputedStyleBase, friend class css_longhand::InternalVisitedTextStrokeColor; friend class css_longhand::LightingColor; friend class css_longhand::OutlineColor; + friend class css_longhand::PointerEvents; friend class css_longhand::Position; friend class css_longhand::Resize; friend class css_longhand::StopColor; @@ -2186,6 +2188,13 @@ class ComputedStyle : public ComputedStyleBase, } void SetIsForcedInert() { SetInertnessInternal(Inertness::kForced); } + // Pointer-events utility functions. + EPointerEvents UsedPointerEvents() const { + if (IsInert()) + return EPointerEvents::kNone; + return PointerEventsInternal(); + } + // Text decoration utility functions. bool TextDecorationVisualOverflowEqual(const ComputedStyle& o) const; void ApplyTextDecorations(const Color& parent_text_decoration_color, @@ -2256,7 +2265,7 @@ class ComputedStyle : public ComputedStyleBase, // Visibility utility functions. bool VisibleToHitTesting() const { return Visibility() == EVisibility::kVisible && - PointerEvents() != EPointerEvents::kNone; + UsedPointerEvents() != EPointerEvents::kNone; } // Animation utility functions. @@ -2693,6 +2702,7 @@ class ComputedStyle : public ComputedStyleBase, private: EClear Clear() const { return ClearInternal(); } EFloat Floating() const { return FloatingInternal(); } + EPointerEvents PointerEvents() const { return PointerEventsInternal(); } EResize Resize() const { return ResizeInternal(); } bool IsInlineSizeContainer() const { diff --git a/blink/renderer/core/svg/svg_svg_element.cc b/blink/renderer/core/svg/svg_svg_element.cc index 3f80a8840d6..8b60e25b857 100644 --- a/blink/renderer/core/svg/svg_svg_element.cc +++ b/blink/renderer/core/svg/svg_svg_element.cc @@ -322,7 +322,7 @@ bool SVGSVGElement::CheckIntersectionOrEnclosure( LayoutObject* layout_object = element.GetLayoutObject(); DCHECK(!layout_object || layout_object->Style()); if (!layout_object || - layout_object->StyleRef().PointerEvents() == EPointerEvents::kNone) + layout_object->StyleRef().UsedPointerEvents() == EPointerEvents::kNone) return false; if (!IsIntersectionOrEnclosureTarget(layout_object)) diff --git a/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-inert.tentative-expected.txt b/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-inert.tentative-expected.txt deleted file mode 100644 index 9dd4bfe5af3..00000000000 --- a/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-inert.tentative-expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL dialog-inert assert_not_equals: Dialog becomes inert dynamically got disallowed value Element node Something -Harness: the test ran to completion. - diff --git a/blink/web_tests/external/wpt/inert/inert-computed-style-expected.txt b/blink/web_tests/external/wpt/inert/inert-computed-style-expected.txt deleted file mode 100644 index 416c46a8e77..00000000000 --- a/blink/web_tests/external/wpt/inert/inert-computed-style-expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL inert isn't hit-testable, but that isn't expose in the computed style assert_equals: inert node is transparent to events (as pointer-events: none) expected Element node
but got Element node
-Harness: the test ran to completion. -