refactor: simplify content_view_ hit-test transparency on macOS#51617
Merged
Conversation
Replace the RootViewMac-level TargetForRect override added in #51586 with a DoesIntersectRect override on content_view_'s own targeter, restoring the structure of #50330 but fixing its actual defect. The original bug (#51576) was that ContentViewTargeterDelegate::TargetForRect returned nullptr when no descendant covered the hit rect, violating the ViewTargeterDelegate contract. RootView::UpdateCursor and RootView::HandleMouseEnteredOrMoved dereference GetEventHandlerForPoint() without null checks, so the nullptr crashed with SIGSEGV when a right-click in a -webkit-app-region: drag region disabled the HTCAPTION early-exit. #51586 fixed the crash by moving the transparency logic to RootViewMac and re-implementing the parent targeter's child-walk loop so it could skip content_view_ and return a sibling instead. That re-implementation duplicates ~25 lines of upstream logic with a subtle rounding divergence (ToEnclosedRectIgnoringError vs ToEnclosingRect), and threads a new content_view_hit_test_transparent_ flag through the platform-neutral NativeWindow/BrowserWindow headers. The same fall-through can be achieved with the existing hit-test hook: override DoesIntersectRect on content_view_ to return false when no visible, processable child intersects the rect. The parent's default TargetForRect loop already skips children whose HitTestRect is false, so hit-testing naturally continues to the WebContentsView sibling and resolves to its NativeViewHost (kSubView) without ever returning nullptr from TargetForRect or re-implementing the walk. This reverts the NativeWindow flag, the BrowserWindow constructor change, and the RootViewMacTargeterDelegate, leaving the fix entirely in native_window_mac.mm at the same install site as #50330.
VerteDinde
approved these changes
May 13, 2026
nmggithub
approved these changes
May 13, 2026
|
No Release Notes |
Contributor
|
I was unable to backport this PR to "43-x-y" cleanly; |
Contributor
|
I was unable to backport this PR to "42-x-y" cleanly; |
Contributor
|
@VerteDinde has manually backported this PR to "43-x-y", please check out #51625 |
Contributor
|
@VerteDinde has manually backported this PR to "42-x-y", please check out #51626 |
VerteDinde
added a commit
that referenced
this pull request
May 14, 2026
Backport of #51617 to 42-x-y. Replace the RootViewMac-level TargetForRect override added in #51586 with a DoesIntersectRect override on content_view_'s own targeter, restoring the structure of #50330 but fixing its actual defect. The original bug (#51576) was that ContentViewTargeterDelegate::TargetForRect returned nullptr when no descendant covered the hit rect, violating the ViewTargeterDelegate contract. RootView::UpdateCursor and RootView::HandleMouseEnteredOrMoved dereference GetEventHandlerForPoint() without null checks, so the nullptr crashed with SIGSEGV when a right-click in a -webkit-app-region: drag region disabled the HTCAPTION early-exit. #51586 fixed the crash by moving the transparency logic to RootViewMac and re-implementing the parent targeter's child-walk loop so it could skip content_view_ and return a sibling instead. That re-implementation duplicates ~25 lines of upstream logic with a subtle rounding divergence (ToEnclosedRectIgnoringError vs ToEnclosingRect), and threads a new content_view_hit_test_transparent_ flag through the platform-neutral NativeWindow/BrowserWindow headers. The same fall-through can be achieved with the existing hit-test hook: override DoesIntersectRect on content_view_ to return false when no visible, processable child intersects the rect. The parent's default TargetForRect loop already skips children whose HitTestRect is false, so hit-testing naturally continues to the WebContentsView sibling and resolves to its NativeViewHost (kSubView) without ever returning nullptr from TargetForRect or re-implementing the walk. This reverts the NativeWindow flag, the BrowserWindow constructor change, and the RootViewMacTargeterDelegate, leaving the fix entirely in native_window_mac.mm at the same install site as #50330. Co-authored-by: Claude <svc-devxp-claude@slack-corp.com>
VerteDinde
added a commit
that referenced
this pull request
May 15, 2026
Backport of #51617 to 43-x-y. Replace the RootViewMac-level TargetForRect override added in #51586 with a DoesIntersectRect override on content_view_'s own targeter, restoring the structure of #50330 but fixing its actual defect. The original bug (#51576) was that ContentViewTargeterDelegate::TargetForRect returned nullptr when no descendant covered the hit rect, violating the ViewTargeterDelegate contract. RootView::UpdateCursor and RootView::HandleMouseEnteredOrMoved dereference GetEventHandlerForPoint() without null checks, so the nullptr crashed with SIGSEGV when a right-click in a -webkit-app-region: drag region disabled the HTCAPTION early-exit. #51586 fixed the crash by moving the transparency logic to RootViewMac and re-implementing the parent targeter's child-walk loop so it could skip content_view_ and return a sibling instead. That re-implementation duplicates ~25 lines of upstream logic with a subtle rounding divergence (ToEnclosedRectIgnoringError vs ToEnclosingRect), and threads a new content_view_hit_test_transparent_ flag through the platform-neutral NativeWindow/BrowserWindow headers. The same fall-through can be achieved with the existing hit-test hook: override DoesIntersectRect on content_view_ to return false when no visible, processable child intersects the rect. The parent's default TargetForRect loop already skips children whose HitTestRect is false, so hit-testing naturally continues to the WebContentsView sibling and resolves to its NativeViewHost (kSubView) without ever returning nullptr from TargetForRect or re-implementing the walk. This reverts the NativeWindow flag, the BrowserWindow constructor change, and the RootViewMacTargeterDelegate, leaving the fix entirely in native_window_mac.mm at the same install site as #50330. Co-authored-by: Claude <svc-devxp-claude@slack-corp.com>
ckerr
pushed a commit
that referenced
this pull request
May 19, 2026
fix: simplify content_view_ hit-test transparency on macOS Replace the RootViewMac-level TargetForRect override added in #51586 with a DoesIntersectRect override on content_view_'s own targeter, restoring the structure of #50330 but fixing its actual defect. The original bug (#51576) was that ContentViewTargeterDelegate::TargetForRect returned nullptr when no descendant covered the hit rect, violating the ViewTargeterDelegate contract. RootView::UpdateCursor and RootView::HandleMouseEnteredOrMoved dereference GetEventHandlerForPoint() without null checks, so the nullptr crashed with SIGSEGV when a right-click in a -webkit-app-region: drag region disabled the HTCAPTION early-exit. re-implementing the parent targeter's child-walk loop so it could skip content_view_ and return a sibling instead. That re-implementation duplicates ~25 lines of upstream logic with a subtle rounding divergence (ToEnclosedRectIgnoringError vs ToEnclosingRect), and threads a new content_view_hit_test_transparent_ flag through the platform-neutral NativeWindow/BrowserWindow headers. The same fall-through can be achieved with the existing hit-test hook: override DoesIntersectRect on content_view_ to return false when no visible, processable child intersects the rect. The parent's default TargetForRect loop already skips children whose HitTestRect is false, so hit-testing naturally continues to the WebContentsView sibling and resolves to its NativeViewHost (kSubView) without ever returning nullptr from TargetForRect or re-implementing the walk. This reverts the NativeWindow flag, the BrowserWindow constructor change, and the RootViewMacTargeterDelegate, leaving the fix entirely in native_window_mac.mm at the same install site as #50330. Co-authored-by: GitHub Copilot <copilot@github.com>
jkleinsc
pushed a commit
that referenced
this pull request
May 27, 2026
* chore: remove macos hittest workaround patch Reverts the temporary Chromium patch and restores the original macOS hit-test workaround behavior in Electron. Co-authored-by: Charles Kerr <charles@charleskerr.com> * fix: do not return root from TargetForRect Restore the macOS hit-testing behavior that keeps BrowserWindow web contents interactive when content_view_ has no matching child. Co-authored-by: Charles Kerr <charles@charleskerr.com> * refactor: simplify content_view_ hit-test transparency on macOS (#51617) fix: simplify content_view_ hit-test transparency on macOS Replace the RootViewMac-level TargetForRect override added in #51586 with a DoesIntersectRect override on content_view_'s own targeter, restoring the structure of #50330 but fixing its actual defect. The original bug (#51576) was that ContentViewTargeterDelegate::TargetForRect returned nullptr when no descendant covered the hit rect, violating the ViewTargeterDelegate contract. RootView::UpdateCursor and RootView::HandleMouseEnteredOrMoved dereference GetEventHandlerForPoint() without null checks, so the nullptr crashed with SIGSEGV when a right-click in a -webkit-app-region: drag region disabled the HTCAPTION early-exit. re-implementing the parent targeter's child-walk loop so it could skip content_view_ and return a sibling instead. That re-implementation duplicates ~25 lines of upstream logic with a subtle rounding divergence (ToEnclosedRectIgnoringError vs ToEnclosingRect), and threads a new content_view_hit_test_transparent_ flag through the platform-neutral NativeWindow/BrowserWindow headers. The same fall-through can be achieved with the existing hit-test hook: override DoesIntersectRect on content_view_ to return false when no visible, processable child intersects the rect. The parent's default TargetForRect loop already skips children whose HitTestRect is false, so hit-testing naturally continues to the WebContentsView sibling and resolves to its NativeViewHost (kSubView) without ever returning nullptr from TargetForRect or re-implementing the walk. This reverts the NativeWindow flag, the BrowserWindow constructor change, and the RootViewMacTargeterDelegate, leaving the fix entirely in native_window_mac.mm at the same install site as #50330. Co-authored-by: GitHub Copilot <copilot@github.com> --------- Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: Noah Gregory <nmggithub@electronjs.org> Co-authored-by: Samuel Attard <sam@electronjs.org> Co-authored-by: GitHub Copilot <copilot@github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of Change
Replaces the fix for #51576 that landed in #51586 with a more scoped one. Same crash fix, much smaller surface.
Background
For
BrowserWindowon macOS, theWebContentsViewis added as a sibling ofcontent_view_at lower z-order so that user-added child views paint above web content. Butcontent_view_covers the whole window, so the defaultviewshit-test always stops atcontent_view_before reaching theWebContentsView. After Chromium CL:6574464 (M139) changedBridgedContentView::hitTest:to useGetHitTestResult(), any non-NativeViewHosthit result causesBridgedContentViewto swallow the event — so allloadURLpage interaction broke. #50330 worked around this by makingContentViewTargeterDelegate::TargetForRectreturnnullptrwhen no descendant ofcontent_view_covered the hit rect, so the result would propagate up as null →kOther→[super hitTest:]findsRenderWidgetHostViewCocoa.Returning
nullptrfromViewTargeterDelegate::TargetForRectviolates its contract — for any in-bounds point it must resolve to a descendant or the root, never null (ui/views/view_targeter_delegate.h,ui/views/view.h).RootView::UpdateCursorandRootView::HandleMouseEnteredOrMovedboth callGetEventHandlerForPoint()and dereference the result without a null check (ui/views/widget/root_view.cc:851-853,:864-871). When a right-click in a-webkit-app-region: dragregion temporarily disables draggable regions (electron_ns_window.mm), theHTCAPTIONearly-exit no longer fires, the views path runs, and thenullptrSEGVs (#51576).Why #51586 wasn't the right shape
#51586 fixed the crash, but did so by moving the transparency logic to a new targeter on
RootViewMacthat re-implementsviews::ViewTargeterDelegate::TargetForRect's child-walk loop so it can skipcontent_view_and pick a sibling. That has several problems:viewsmost likely to change (mirroring, layer transforms, visibility semantics, rounding mode). Any upstream change to that loop now needs to be ported by hand or the two will silently diverge.View::ConvertRectToTarget(root, child, rect)(thegfx::Rectoverload, which rounds inward viaToEnclosedRectIgnoringError), while the upstream loop converts to agfx::RectFand rounds outward viaToEnclosingRect. For a 1×1 hit rect on a fractional-DPI display, those can disagree.UsePointBasedTargeting(rect)), so rect-based/touch targeting still falls through to the default — which returnscontent_view_→kRootView— i.e. the originalloadURL-interaction bug is still live for the non-point path. chore: remove macos hittest workaround patch #50330 covered both.native_window.h(the cross-platform base) grew acontent_view_hit_test_transparent_flag + getter + setter that onlynative_window_mac.mmreads, andBrowserWindow's constructor (also platform-neutral) grew aset_content_view_hit_test_transparent(true)that does nothing on Windows/Linux.return skipped_content_view ? skipped_content_view : root;fallback returnscontent_view_→kRootView→ swallowed — the exact behavior chore: remove macos hittest workaround patch #50330 was fixing. It's unreachable today only becauseWebContentsViewalways covers the window; if the view structure changes, this re-introduces the bug.content_view_, not something its parent's targeter should have special knowledge of.What this PR does instead
The
viewshit-test machinery already has a hook for "is this view opaque to events at this rect?" —ViewTargeterDelegate::DoesIntersectRect, whichView::HitTestRectconsults. The parent's defaultTargetForRectloop already checkschild->HitTestRect()and skips children that say no (view_targeter_delegate.cc:61-63). So we can fix #50330 in place: keep the targeter oncontent_view_, keep the same install site inSetContentView, and overrideDoesIntersectRectto returnfalsewhen no visible, processable child ofcontent_view_covers the rect. The parent's default loop then falls through to theWebContentsViewsibling and resolves to itsNativeViewHost—kSubView→ routes toRenderWidgetHostViewCocoa— without ever returningnullptrfromTargetForRector duplicating the upstream walk.This reverts the
NativeWindowflag, theBrowserWindowconstructor change, andRootViewMacTargeterDelegate. The net change vs the buggy #50330 state is a single method-body swap insidenative_window_mac.mm.Verification
Verified on macOS 26.4 (25E246), arm64, driving input with real OS-level
CGEventPostevents so theNSWindow→BridgedContentView::hitTest:→RootView::UpdateCursor→ targeter path is actually exercised:loadURLinteraction (the chore: remove macos hittest workaround patch #50330 regression check): button click, input focus + typing, hover →pointingHandcursor, link click — all work.-webkit-app-region: drag(the Crash (SIGSEGV) on right-click in -webkit-app-region: drag on macOS 26 (Tahoe) #51576 crash check): right-click bar, mouse-move over bar, drag (window moved), Ctrl+click, right/left-click content — no SIGSEGV on any step.WebContentsViewover web content: clicking aWebContentsViewoverlaid oncontent_view_and clicking the background page both route correctly;DoesIntersectRectreturns true over the overlay child and false outside it.api-browser-window-spec.ts -g "BrowserView|contentView|setContentView": 4/4.api-web-contents-view-spec.ts: 29/29.drag-region-spec.ts: 6/6 (8 skip, non-macOS).Backports
41-x-yis not affected — chore: remove macos hittest workaround patch #50330 was never backported there; the original Chromium revert patch is still in place. (fix: don't return anullptrfromTargetForRect(#51586) #51611 was correctly closed unmerged.)42-x-y/43-x-y: the open fix: don't return anullptrfromTargetForRect#51586 backports (fix: don't return anullptrfromTargetForRect#51605, fix: don't return anullptrfromTargetForRect#51606) should be replaced with backports of this PR once it lands.Checklist
npm testpassesRelease Notes
Notes: none