Guard portal refreshes and reset plain reattached web views

This commit is contained in:
Lawrence Chen 2026-03-10 21:41:49 -07:00
parent a58cd76e2e
commit 83c7c9ee19

View file

@ -1672,9 +1672,13 @@ final class WindowBrowserSlotView: NSView {
func pinHostedWebView(_ webView: WKWebView) {
guard webView.superview === self else { return }
let needsPlainWebViewFrameReset =
!Self.hasWebKitCompanionSubview(in: self, primaryWebView: webView) &&
Self.frameDiffersFromBounds(webView.frame, bounds: bounds)
let needsFrameHosting =
hostedWebView !== webView ||
!hostedWebViewConstraints.isEmpty ||
needsPlainWebViewFrameReset ||
!webView.translatesAutoresizingMaskIntoConstraints ||
webView.autoresizingMask != [.width, .height]
guard needsFrameHosting else {
@ -1687,8 +1691,8 @@ final class WindowBrowserSlotView: NSView {
hostedWebViewConstraints = []
hostedWebView = webView
// Attached Web Inspector mutates the moved WKWebView's frame directly.
// Re-pin only when hosting mode changes, not when WebKit resizes the page
// inside the slot for side-docked DevTools.
// Re-pin plain web views after cross-host reattach, but preserve the
// WebKit-managed split frame when docked DevTools siblings are present.
webView.translatesAutoresizingMaskIntoConstraints = true
webView.autoresizingMask = [.width, .height]
webView.frame = bounds
@ -1696,6 +1700,27 @@ final class WindowBrowserSlotView: NSView {
layoutSubtreeIfNeeded()
}
private static func frameDiffersFromBounds(_ frame: NSRect, bounds: NSRect, epsilon: CGFloat = 0.5) -> Bool {
abs(frame.minX - bounds.minX) > epsilon ||
abs(frame.minY - bounds.minY) > epsilon ||
abs(frame.width - bounds.width) > epsilon ||
abs(frame.height - bounds.height) > epsilon
}
private static func hasWebKitCompanionSubview(in host: NSView, primaryWebView: WKWebView) -> Bool {
var stack = host.subviews.filter { $0 !== primaryWebView }
while let current = stack.popLast() {
if current.isDescendant(of: primaryWebView) {
continue
}
if String(describing: type(of: current)).contains("WK") {
return true
}
stack.append(contentsOf: current.subviews)
}
return false
}
func effectivePaneTopChromeHeight() -> CGFloat {
paneTopChromeHeight
}
@ -1975,6 +2000,7 @@ final class WindowBrowserPortal: NSObject {
guard let webView = entry.webView,
let containerView = entry.containerView,
!containerView.isHidden else { continue }
guard webView.superview === containerView else { continue }
refreshHostedWebViewPresentation(
webView,
in: containerView,
@ -2650,7 +2676,7 @@ final class WindowBrowserPortal: NSObject {
containerView.setPaneTopChromeHeight(0)
containerView.setSearchOverlay(nil)
containerView.setDropZoneOverlay(zone: nil)
if !containerView.isHidden {
if !containerView.isHidden, webView.superview === containerView {
webView.browserPortalNotifyHidden(reason: reason)
}
containerView.isHidden = true