Skip to content

chore: remove macos hittest workaround patch#50330

Merged
jkleinsc merged 1 commit into
mainfrom
view-macos-fixup
Mar 19, 2026
Merged

chore: remove macos hittest workaround patch#50330
jkleinsc merged 1 commit into
mainfrom
view-macos-fixup

Conversation

@codebytere

Copy link
Copy Markdown
Member

Description of Change

CL:6574464 changed BridgedContentView::hitTest: to use GetHitTestResult(), which returns kRootView for any non-null, non-NativeViewHost view — causing BridgedContentView to absorb all web content mouse events. In BrowserWindow, content_view_ sits in front of the sibling WebContentsView and covers the full client area, so it was always found first, breaking all loadURL page interaction.

Fix this by installing a ContentViewTargeterDelegate on content_view_ in NativeWindowMac::SetContentView that returns nullptr (instead of the view itself) when no children cover the target point. This makes GetHitTestResult return kOther, allowing hitTest: to fall through to [super hitTest:] and find RenderWidgetHostViewCocoa. This also removes the now-unnecessary chromium partial-revert patch that worked around the same issue.

Checklist

Release Notes

Notes: none

@codebytere codebytere marked this pull request as ready for review March 18, 2026 09:01
@codebytere codebytere requested a review from a team as a code owner March 18, 2026 09:01
@codebytere codebytere added semver/patch backwards-compatible bug fixes target/41-x-y PR should also be added to the "41-x-y" branch. target/42-x-y PR should also be added to the "42-x-y" branch. labels Mar 18, 2026
@codebytere codebytere self-assigned this Mar 18, 2026
CL:6574464 changed BridgedContentView::hitTest: to use GetHitTestResult(), which
returns kRootView for any non-null, non-NativeViewHost view — causing
BridgedContentView to absorb all web content mouse events. In BrowserWindow,
content_view_ sits in front of the sibling WebContentsView and covers the full
client area, so it was always found first, breaking all loadURL page interaction.

Fix this by installing a ContentViewTargeterDelegate on content_view_ in
NativeWindowMac::SetContentView that returns nullptr (instead of the view itself)
when no children cover the target point. This makes GetHitTestResult return kOther,
allowing hitTest: to fall through to [super hitTest:] and find
RenderWidgetHostViewCocoa. This also removes the now-unnecessary chromium
partial-revert patch that worked around the same issue.
@codebytere codebytere removed their assignment Mar 18, 2026
@jkleinsc jkleinsc changed the title build: remove macos hittest workaround patch chore: remove macos hittest workaround patch Mar 18, 2026
@electron-cation electron-cation Bot added new-pr 🌱 PR opened recently and removed new-pr 🌱 PR opened recently labels Mar 18, 2026
Comment on lines +119 to +137
// A ViewTargeterDelegate installed on content_view_ to make it event-
// transparent when no children cover the target point.
//
// In BrowserWindow, the WebContentsView is added as a sibling of content_view_
// at a lower Z-order (behind it) so that user-added child views paint above
// the web content. However, views::ViewTargeterDelegate::TargetForRect
// iterates children front-to-back and returns the first child whose
// HitTestRect() is true. content_view_ covers the full window area, so the
// WebContentsView (and its NativeViewHost) is never reached.
//
// Chromium's BridgedContentView::hitTest: uses GetHitTestResult() to classify
// the result: NativeViewHost → kSubView (routes to RenderWidgetHostViewCocoa);
// anything else non-null → kRootView (BridgedContentView absorbs the event,
// breaking all web content interaction with loadURL); null → kOther (falls
// through to [super hitTest:] which finds RenderWidgetHostViewCocoa directly).
//
// By returning nullptr instead of root when no children cover the target rect,
// GetEventHandlerForPoint propagates null up the chain → GetHitTestResult
// returns kOther → hitTest: falls through to [super hitTest:] → NSView walk

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the detailed explanation here!

@jkleinsc jkleinsc merged commit e31a95b into main Mar 19, 2026
113 of 114 checks passed
@jkleinsc jkleinsc deleted the view-macos-fixup branch March 19, 2026 15:04
@release-clerk

release-clerk Bot commented Mar 19, 2026

Copy link
Copy Markdown

No Release Notes

@trop

trop Bot commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

I was unable to backport this PR to "41-x-y" cleanly;
you will need to perform this backport manually.

@trop trop Bot added needs-manual-bp/41-x-y and removed target/41-x-y PR should also be added to the "41-x-y" branch. labels Mar 19, 2026
@trop

trop Bot commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

I have automatically backported this PR to "42-x-y", please check out #50374

@trop trop Bot added in-flight/42-x-y and removed target/42-x-y PR should also be added to the "42-x-y" branch. in-flight/42-x-y labels Mar 19, 2026
@trop trop Bot added the merged/42-x-y PR was merged to the "42-x-y" branch. label Mar 19, 2026
@ckerr

ckerr commented May 13, 2026

Copy link
Copy Markdown
Member

I was unable to backport this PR to "41-x-y" cleanly; you will need to perform this backport manually.

Note: This PR introduces a nullptr dereference regression fixed by #51586 . If/when we backport this PR to 41-x-y, we should pick up 51586 as well.

MarshallOfSound added a commit that referenced this pull request May 14, 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.

#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 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>
@trop

trop Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

@ckerr has manually backported this PR to "41-x-y", please check out #51699

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>
@trop trop Bot added merged/41-x-y PR was merged to the "41-x-y" branch. and removed in-flight/41-x-y labels May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged/41-x-y PR was merged to the "41-x-y" branch. merged/42-x-y PR was merged to the "42-x-y" branch. semver/patch backwards-compatible bug fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants