* Fix browser pane stuck in HTML fullscreen (#6442) Guest content in a browser pane could enter HTML fullscreen but not exit it: requestFullscreen() resized the host BrowserWindow into native fullscreen, and exitFullscreen() had nothing to restore, leaving the pane stuck. Set the webview's disableHtmlFullscreenWindowResize preference so HTML fullscreen is contained to the <webview> element. Exit then works and fullscreenchange fires as guests expect. * Apply browser guest fullscreen policy consistently Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Wolfgang Schoenberger <221313372+wolfiesch@users.noreply.github.com> Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com> Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
66b54c4f49
commit
1f968b92c9
|
|
@ -1,6 +1,7 @@
|
|||
import { randomUUID } from 'crypto'
|
||||
import { BrowserWindow } from 'electron'
|
||||
import { ORCA_BROWSER_PARTITION } from '../../shared/constants'
|
||||
import { ORCA_BROWSER_GUEST_WEB_PREFERENCES } from '../../shared/browser-guest-web-preferences'
|
||||
import type { BrowserBackend, BrowserBackendCreateTab } from './browser-backend'
|
||||
import type { BrowserManager } from './browser-manager'
|
||||
import { browserSessionRegistry } from './browser-session-registry'
|
||||
|
|
@ -35,6 +36,9 @@ export class OffscreenBrowserBackend implements BrowserBackend {
|
|||
width: DEFAULT_VIEWPORT_WIDTH,
|
||||
height: DEFAULT_VIEWPORT_HEIGHT,
|
||||
webPreferences: {
|
||||
// Why: offscreen pages are the SSH/headless browser backend; keep their
|
||||
// HTML fullscreen behavior aligned with desktop <webview> guests.
|
||||
...ORCA_BROWSER_GUEST_WEB_PREFERENCES,
|
||||
partition,
|
||||
sandbox: true,
|
||||
contextIsolation: true,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
import { readFileSync } from 'fs'
|
||||
import { resolve } from 'path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const OFFSCREEN_BACKEND_SOURCE = resolve(__dirname, 'offscreen-browser-backend.ts')
|
||||
|
||||
function sourceBetween(source: string, start: string, end: string): string {
|
||||
const startIndex = source.indexOf(start)
|
||||
const endIndex = source.indexOf(end, startIndex + start.length)
|
||||
|
||||
expect(startIndex).toBeGreaterThanOrEqual(0)
|
||||
expect(endIndex).toBeGreaterThan(startIndex)
|
||||
|
||||
return source.slice(startIndex, endIndex)
|
||||
}
|
||||
|
||||
describe('OffscreenBrowserBackend web preferences', () => {
|
||||
it('uses the shared browser guest fullscreen policy', () => {
|
||||
const source = readFileSync(OFFSCREEN_BACKEND_SOURCE, 'utf8')
|
||||
const webPreferencesBlock = sourceBetween(source, 'webPreferences: {', 'partition,')
|
||||
|
||||
expect(source).toContain(
|
||||
"import { ORCA_BROWSER_GUEST_WEB_PREFERENCES } from '../../shared/browser-guest-web-preferences'"
|
||||
)
|
||||
expect(webPreferencesBlock).toContain('...ORCA_BROWSER_GUEST_WEB_PREFERENCES')
|
||||
})
|
||||
})
|
||||
|
|
@ -225,6 +225,11 @@ describe('createMainWindow', () => {
|
|||
{ src: 'data:text/html,' } as never
|
||||
)
|
||||
expect(allowBlankEvent.preventDefault).not.toHaveBeenCalled()
|
||||
expect(allowBlankPrefs).toMatchObject({
|
||||
disableHtmlFullscreenWindowResize: true,
|
||||
partition: 'persist:orca-browser',
|
||||
sandbox: true
|
||||
})
|
||||
|
||||
const denyInlineHtmlEvent = { preventDefault: vi.fn() }
|
||||
windowHandlers['will-attach-webview'](
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import {
|
|||
normalizeBrowserNavigationUrl,
|
||||
normalizeExternalBrowserUrl
|
||||
} from '../../shared/browser-url'
|
||||
import { ORCA_BROWSER_GUEST_WEB_PREFERENCES } from '../../shared/browser-guest-web-preferences'
|
||||
import { isCrashReportReason } from '../../shared/crash-reporting'
|
||||
import {
|
||||
getWindowShortcutActionId,
|
||||
|
|
@ -485,6 +486,9 @@ export function createMainWindow(
|
|||
webPreferences.allowRunningInsecureContent = false
|
||||
webPreferences.contextIsolation = true
|
||||
webPreferences.sandbox = true
|
||||
// Why: keep renderer-created webviews aligned with the browser guest policy
|
||||
// even if the host markup omits or misspells a preference.
|
||||
Object.assign(webPreferences, ORCA_BROWSER_GUEST_WEB_PREFERENCES)
|
||||
// Why: preserve the registry-validated partition instead of forcing the
|
||||
// legacy constant. This lets imported/isolated session profiles use their
|
||||
// own cookie/storage partition while keeping all other hardening intact.
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ import {
|
|||
browserViewportPresetToOverride,
|
||||
getBrowserViewportPreset
|
||||
} from '../../../../shared/browser-viewport-presets'
|
||||
import { ORCA_BROWSER_GUEST_WEB_PREFERENCES_ATTRIBUTE } from '../../../../shared/browser-guest-web-preferences'
|
||||
import { rememberLiveBrowserUrl } from './browser-runtime'
|
||||
import {
|
||||
destroyPersistentWebview,
|
||||
|
|
@ -3612,6 +3613,16 @@ function BrowserPagePane({
|
|||
webview = document.createElement('webview') as Electron.WebviewTag
|
||||
webview.setAttribute('partition', webviewPartition)
|
||||
webview.setAttribute('allowpopups', '')
|
||||
// Why: keep HTML fullscreen contained to the <webview> element instead of
|
||||
// letting guest content resize the host BrowserWindow into native macOS
|
||||
// fullscreen. Without this, requestFullscreen() resizes the OS window but
|
||||
// exitFullscreen() has nothing to restore, leaving the pane stuck
|
||||
// fullscreen (issue #6442). Containing fullscreen to the element makes
|
||||
// exit reliable and fires fullscreenchange as guests expect.
|
||||
// Why: the key must be camelCase — Electron's <webview> webpreferences
|
||||
// parser spreads keys verbatim into WebPreferences, so a lowercase key is
|
||||
// silently ignored.
|
||||
webview.setAttribute('webpreferences', ORCA_BROWSER_GUEST_WEB_PREFERENCES_ATTRIBUTE)
|
||||
webview.style.display = 'flex'
|
||||
webview.style.flex = '1'
|
||||
webview.style.width = '100%'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
import { readFileSync } from 'fs'
|
||||
import { resolve } from 'path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const BROWSER_PANE_SOURCE = resolve(__dirname, 'BrowserPane.tsx')
|
||||
|
||||
function browserPaneSource(): string {
|
||||
return readFileSync(BROWSER_PANE_SOURCE, 'utf8')
|
||||
}
|
||||
|
||||
function sourceBetween(source: string, start: string, end: string): string {
|
||||
const startIndex = source.indexOf(start)
|
||||
const endIndex = source.indexOf(end, startIndex + start.length)
|
||||
|
||||
expect(startIndex).toBeGreaterThanOrEqual(0)
|
||||
expect(endIndex).toBeGreaterThan(startIndex)
|
||||
|
||||
return source.slice(startIndex, endIndex)
|
||||
}
|
||||
|
||||
describe('BrowserPane webview preferences', () => {
|
||||
it('keeps HTML fullscreen contained inside the browser pane webview', () => {
|
||||
const source = browserPaneSource()
|
||||
const creationBlock = sourceBetween(
|
||||
source,
|
||||
"webview = document.createElement('webview')",
|
||||
'registerPersistentWebview'
|
||||
)
|
||||
|
||||
expect(source).toContain(
|
||||
"import { ORCA_BROWSER_GUEST_WEB_PREFERENCES_ATTRIBUTE } from '../../../../shared/browser-guest-web-preferences'"
|
||||
)
|
||||
expect(creationBlock).toContain(
|
||||
"webview.setAttribute('webpreferences', ORCA_BROWSER_GUEST_WEB_PREFERENCES_ATTRIBUTE)"
|
||||
)
|
||||
expect(creationBlock).not.toContain('disablehtmlfullscreenwindowresize')
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export const ORCA_BROWSER_GUEST_WEB_PREFERENCES = {
|
||||
disableHtmlFullscreenWindowResize: true
|
||||
} as const
|
||||
|
||||
export const ORCA_BROWSER_GUEST_WEB_PREFERENCES_ATTRIBUTE = 'disableHtmlFullscreenWindowResize=true'
|
||||
Loading…
Reference in New Issue