X Tutup
Skip to content

Commit 5e10965

Browse files
committed
fix: html fullscreen transitions stacking
1 parent 90f17e4 commit 5e10965

File tree

10 files changed

+158
-52
lines changed

10 files changed

+158
-52
lines changed

shell/browser/api/electron_api_web_contents.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3510,7 +3510,12 @@ void WebContents::EnumerateDirectory(
35103510

35113511
bool WebContents::IsFullscreenForTabOrPending(
35123512
const content::WebContents* source) {
3513-
return html_fullscreen_;
3513+
bool transition_fs = owner_window()
3514+
? owner_window()->fullscreen_transition_state() !=
3515+
NativeWindow::FullScreenTransitionState::NONE
3516+
: false;
3517+
3518+
return html_fullscreen_ || transition_fs;
35143519
}
35153520

35163521
bool WebContents::TakeFocus(content::WebContents* source, bool reverse) {
@@ -3833,9 +3838,8 @@ void WebContents::SetHtmlApiFullscreen(bool enter_fullscreen) {
38333838
? !web_preferences->ShouldDisableHtmlFullscreenWindowResize()
38343839
: true;
38353840

3836-
if (html_fullscreenable) {
3841+
if (html_fullscreenable)
38373842
owner_window_->SetFullScreen(enter_fullscreen);
3838-
}
38393843

38403844
UpdateHtmlApiFullscreen(enter_fullscreen);
38413845
native_fullscreen_ = false;

shell/browser/native_window.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,15 @@ std::string NativeWindow::GetAccessibleTitle() {
709709
return base::UTF16ToUTF8(accessible_title_);
710710
}
711711

712+
void NativeWindow::HandlePendingFullscreenTransitions() {
713+
if (pending_transitions_.empty())
714+
return;
715+
716+
bool next_transition = pending_transitions_.front();
717+
pending_transitions_.pop();
718+
SetFullScreen(next_transition);
719+
}
720+
712721
// static
713722
int32_t NativeWindow::next_id_ = 0;
714723

shell/browser/native_window.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <list>
99
#include <memory>
10+
#include <queue>
1011
#include <string>
1112
#include <vector>
1213

@@ -317,6 +318,17 @@ class NativeWindow : public base::SupportsUserData,
317318
observers_.RemoveObserver(obs);
318319
}
319320

321+
enum class FullScreenTransitionState { ENTERING, EXITING, NONE };
322+
323+
// Handle fullscreen transitions.
324+
void HandlePendingFullscreenTransitions();
325+
void set_fullscreen_transition_state(FullScreenTransitionState state) {
326+
fullscreen_transition_state_ = state;
327+
}
328+
FullScreenTransitionState fullscreen_transition_state() const {
329+
return fullscreen_transition_state_;
330+
}
331+
320332
views::Widget* widget() const { return widget_.get(); }
321333
views::View* content_view() const { return content_view_; }
322334

@@ -371,6 +383,10 @@ class NativeWindow : public base::SupportsUserData,
371383
// The "titleBarStyle" option.
372384
TitleBarStyle title_bar_style_ = TitleBarStyle::kNormal;
373385

386+
std::queue<bool> pending_transitions_;
387+
FullScreenTransitionState fullscreen_transition_state_ =
388+
FullScreenTransitionState::NONE;
389+
374390
private:
375391
std::unique_ptr<views::Widget> widget_;
376392

shell/browser/native_window_mac.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#import <Cocoa/Cocoa.h>
99

1010
#include <memory>
11-
#include <queue>
1211
#include <string>
1312
#include <vector>
1413

@@ -171,12 +170,6 @@ class NativeWindowMac : public NativeWindow,
171170
void SetCollectionBehavior(bool on, NSUInteger flag);
172171
void SetWindowLevel(int level);
173172

174-
enum class FullScreenTransitionState { ENTERING, EXITING, NONE };
175-
176-
// Handle fullscreen transitions.
177-
void SetFullScreenTransitionState(FullScreenTransitionState state);
178-
void HandlePendingFullscreenTransitions();
179-
180173
enum class VisualEffectState {
181174
kFollowWindow,
182175
kActive,
@@ -242,13 +235,6 @@ class NativeWindowMac : public NativeWindow,
242235
bool zoom_to_page_width_ = false;
243236
absl::optional<gfx::Point> traffic_light_position_;
244237

245-
std::queue<bool> pending_transitions_;
246-
FullScreenTransitionState fullscreen_transition_state() const {
247-
return fullscreen_transition_state_;
248-
}
249-
FullScreenTransitionState fullscreen_transition_state_ =
250-
FullScreenTransitionState::NONE;
251-
252238
NSInteger attention_request_id_ = 0; // identifier from requestUserAttention
253239

254240
// The presentation options before entering kiosk mode.

shell/browser/native_window_mac.mm

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -578,11 +578,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
578578
return [window_ isVisible] && !occluded && !IsMinimized();
579579
}
580580

581-
void NativeWindowMac::SetFullScreenTransitionState(
582-
FullScreenTransitionState state) {
583-
fullscreen_transition_state_ = state;
584-
}
585-
586581
bool NativeWindowMac::IsEnabled() {
587582
return [window_ attachedSheet] == nil;
588583
}
@@ -645,15 +640,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
645640
return [window_ isMiniaturized];
646641
}
647642

648-
void NativeWindowMac::HandlePendingFullscreenTransitions() {
649-
if (pending_transitions_.empty())
650-
return;
651-
652-
bool next_transition = pending_transitions_.front();
653-
pending_transitions_.pop();
654-
SetFullScreen(next_transition);
655-
}
656-
657643
void NativeWindowMac::SetFullScreen(bool fullscreen) {
658644
// [NSWindow -toggleFullScreen] is an asynchronous operation, which means
659645
// that it's possible to call it while a fullscreen transition is currently

shell/browser/ui/cocoa/electron_ns_window_delegate.mm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ - (void)windowDidEndLiveResize:(NSNotification*)notification {
234234
}
235235

236236
- (void)windowWillEnterFullScreen:(NSNotification*)notification {
237-
shell_->SetFullScreenTransitionState(FullScreenTransitionState::ENTERING);
237+
shell_->set_fullscreen_transition_state(FullScreenTransitionState::ENTERING);
238238

239239
shell_->NotifyWindowWillEnterFullScreen();
240240

@@ -244,21 +244,21 @@ - (void)windowWillEnterFullScreen:(NSNotification*)notification {
244244
}
245245

246246
- (void)windowDidEnterFullScreen:(NSNotification*)notification {
247-
shell_->SetFullScreenTransitionState(FullScreenTransitionState::NONE);
247+
shell_->set_fullscreen_transition_state(FullScreenTransitionState::NONE);
248248

249249
shell_->NotifyWindowEnterFullScreen();
250250

251251
shell_->HandlePendingFullscreenTransitions();
252252
}
253253

254254
- (void)windowWillExitFullScreen:(NSNotification*)notification {
255-
shell_->SetFullScreenTransitionState(FullScreenTransitionState::EXITING);
255+
shell_->set_fullscreen_transition_state(FullScreenTransitionState::EXITING);
256256

257257
shell_->NotifyWindowWillLeaveFullScreen();
258258
}
259259

260260
- (void)windowDidExitFullScreen:(NSNotification*)notification {
261-
shell_->SetFullScreenTransitionState(FullScreenTransitionState::NONE);
261+
shell_->set_fullscreen_transition_state(FullScreenTransitionState::NONE);
262262

263263
shell_->SetResizable(is_resizable_);
264264
shell_->NotifyWindowLeaveFullScreen();

spec-main/api-browser-window-spec.ts

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4299,6 +4299,8 @@ describe('BrowserWindow module', () => {
42994299
});
43004300

43014301
ifdescribe(process.platform === 'darwin')('fullscreen state', () => {
4302+
afterEach(closeAllWindows);
4303+
43024304
it('should not cause a crash if called when exiting fullscreen', async () => {
43034305
const w = new BrowserWindow();
43044306

@@ -4348,19 +4350,80 @@ describe('BrowserWindow module', () => {
43484350
expect(w.isFullScreen()).to.be.false('is fullscreen');
43494351
});
43504352

4353+
it('handles several HTML fullscreen transitions', async () => {
4354+
const w = new BrowserWindow();
4355+
await w.loadFile(path.join(fixtures, 'pages', 'a.html'));
4356+
4357+
expect(w.isFullScreen()).to.be.false('is fullscreen');
4358+
4359+
const enterFullScreen = emittedOnce(w, 'enter-full-screen');
4360+
const leaveFullScreen = emittedOnce(w, 'leave-full-screen');
4361+
4362+
await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
4363+
await enterFullScreen;
4364+
await w.webContents.executeJavaScript('document.exitFullscreen()', true);
4365+
await leaveFullScreen;
4366+
4367+
expect(w.isFullScreen()).to.be.false('is fullscreen');
4368+
4369+
await delay();
4370+
4371+
await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
4372+
await enterFullScreen;
4373+
await w.webContents.executeJavaScript('document.exitFullscreen()', true);
4374+
await leaveFullScreen;
4375+
4376+
expect(w.isFullScreen()).to.be.false('is fullscreen');
4377+
});
4378+
43514379
it('handles several transitions in close proximity', async () => {
43524380
const w = new BrowserWindow();
43534381

43544382
expect(w.isFullScreen()).to.be.false('is fullscreen');
43554383

4384+
const enterFS = emittedNTimes(w, 'enter-full-screen', 2);
4385+
const leaveFS = emittedNTimes(w, 'leave-full-screen', 2);
4386+
43564387
w.setFullScreen(true);
43574388
w.setFullScreen(false);
43584389
w.setFullScreen(true);
4390+
w.setFullScreen(false);
43594391

4360-
const enterFullScreen = emittedNTimes(w, 'enter-full-screen', 2);
4361-
await enterFullScreen;
4392+
await Promise.all([enterFS, leaveFS]);
43624393

4363-
expect(w.isFullScreen()).to.be.true('not fullscreen');
4394+
expect(w.isFullScreen()).to.be.false('not fullscreen');
4395+
});
4396+
4397+
it('handles several chromium-initiated transitions in close proximity', async () => {
4398+
const w = new BrowserWindow();
4399+
await w.loadFile(path.join(fixtures, 'pages', 'a.html'));
4400+
4401+
expect(w.isFullScreen()).to.be.false('is fullscreen');
4402+
4403+
let enterCount = 0;
4404+
let exitCount = 0;
4405+
4406+
const done = new Promise<void>(resolve => {
4407+
const checkDone = () => {
4408+
if (enterCount === 2 && exitCount === 2) resolve();
4409+
};
4410+
4411+
w.webContents.on('enter-html-full-screen', () => {
4412+
enterCount++;
4413+
checkDone();
4414+
});
4415+
4416+
w.webContents.on('leave-html-full-screen', () => {
4417+
exitCount++;
4418+
checkDone();
4419+
});
4420+
});
4421+
4422+
await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
4423+
await w.webContents.executeJavaScript('document.exitFullscreen()');
4424+
await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
4425+
await w.webContents.executeJavaScript('document.exitFullscreen()');
4426+
await done;
43644427
});
43654428

43664429
it('does not crash when exiting simpleFullScreen (properties)', async () => {

spec-main/chromium-spec.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import * as url from 'url';
1010
import * as ChildProcess from 'child_process';
1111
import { EventEmitter } from 'events';
1212
import { promisify } from 'util';
13-
import { ifit, ifdescribe, delay, defer } from './spec-helpers';
13+
import { ifit, ifdescribe, defer, delay } from './spec-helpers';
1414
import { AddressInfo } from 'net';
1515
import { PipeTransport } from './pipe-transport';
1616

@@ -1590,7 +1590,7 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', ()
15901590
server.close();
15911591
});
15921592

1593-
it('can fullscreen from out-of-process iframes (OOPIFs)', async () => {
1593+
ifit(process.platform !== 'darwin')('can fullscreen from out-of-process iframes (OOPIFs)', async () => {
15941594
const fullscreenChange = emittedOnce(ipcMain, 'fullscreenChange');
15951595
const html =
15961596
'<iframe style="width: 0" frameborder=0 src="http://localhost:8989" allowfullscreen></iframe>';
@@ -1614,7 +1614,36 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', ()
16141614
expect(width).to.equal(0);
16151615
});
16161616

1617+
ifit(process.platform === 'darwin')('can fullscreen from out-of-process iframes (OOPIFs)', async () => {
1618+
await emittedOnce(w, 'enter-full-screen');
1619+
const fullscreenChange = emittedOnce(ipcMain, 'fullscreenChange');
1620+
const html =
1621+
'<iframe style="width: 0" frameborder=0 src="http://localhost:8989" allowfullscreen></iframe>';
1622+
w.loadURL(`data:text/html,${html}`);
1623+
await fullscreenChange;
1624+
1625+
const fullscreenWidth = await w.webContents.executeJavaScript(
1626+
"document.querySelector('iframe').offsetWidth"
1627+
);
1628+
expect(fullscreenWidth > 0).to.be.true();
1629+
1630+
await w.webContents.executeJavaScript(
1631+
"document.querySelector('iframe').contentWindow.postMessage('exitFullscreen', '*')"
1632+
);
1633+
await emittedOnce(w.webContents, 'leave-html-full-screen');
1634+
1635+
const width = await w.webContents.executeJavaScript(
1636+
"document.querySelector('iframe').offsetWidth"
1637+
);
1638+
expect(width).to.equal(0);
1639+
1640+
w.setFullScreen(false);
1641+
await emittedOnce(w, 'leave-full-screen');
1642+
});
1643+
16171644
it('can fullscreen from in-process iframes', async () => {
1645+
if (process.platform === 'darwin') await emittedOnce(w, 'enter-full-screen');
1646+
16181647
const fullscreenChange = emittedOnce(ipcMain, 'fullscreenChange');
16191648
w.loadFile(path.join(fixturesPath, 'pages', 'fullscreen-ipif.html'));
16201649
await fullscreenChange;

spec-main/webview-spec.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,16 +436,32 @@ describe('<webview> tag', function () {
436436

437437
afterEach(closeAllWindows);
438438

439-
it('should make parent frame element fullscreen too', async () => {
439+
ifit(process.platform !== 'darwin')('should make parent frame element fullscreen too', async () => {
440440
const [w, webview] = await loadWebViewWindow();
441441
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.false();
442442

443443
const parentFullscreen = emittedOnce(ipcMain, 'fullscreenchange');
444444
await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
445445
await parentFullscreen;
446+
446447
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.true();
447448
});
448449

450+
ifit(process.platform === 'darwin')('should make parent frame element fullscreen too', async () => {
451+
const [w, webview] = await loadWebViewWindow();
452+
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.false();
453+
454+
const parentFullscreen = emittedOnce(ipcMain, 'fullscreenchange');
455+
const enterHTMLFS = emittedOnce(w.webContents, 'enter-html-full-screen');
456+
const leaveHTMLFS = emittedOnce(w.webContents, 'leave-html-full-screen');
457+
458+
await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
459+
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.true();
460+
461+
await webview.executeJavaScript('document.exitFullscreen()');
462+
await Promise.all([enterHTMLFS, leaveHTMLFS, parentFullscreen]);
463+
});
464+
449465
// FIXME(zcbenz): Fullscreen events do not work on Linux.
450466
// This test is flaky on arm64 macOS.
451467
ifit(process.platform !== 'linux' && process.arch !== 'arm64')('exiting fullscreen should unfullscreen window', async () => {

spec/webview-spec.js

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -911,17 +911,14 @@ describe('<webview> tag', function () {
911911

912912
describe('executeJavaScript', () => {
913913
it('should support user gesture', async () => {
914-
await loadWebView(webview, {
915-
src: `file://${fixtures}/pages/fullscreen.html`
916-
});
917-
918-
// Event handler has to be added before js execution.
919-
const waitForEnterHtmlFullScreen = waitForEvent(webview, 'enter-html-full-screen');
920-
921-
const jsScript = "document.querySelector('video').webkitRequestFullscreen()";
922-
webview.executeJavaScript(jsScript, true);
923-
924-
return waitForEnterHtmlFullScreen;
914+
await loadWebView(webview, { src: `file://${fixtures}/pages/base-page.html` });
915+
webview.executeJavaScript(`
916+
const audio = document.createElement("audio")
917+
audio.src = "../assets/tone.wav"
918+
document.body.appendChild(audio);
919+
audio.play()
920+
`, true);
921+
await waitForEvent(webview, 'media-started-playing');
925922
});
926923

927924
it('can return the result of the executed script', async () => {

0 commit comments

Comments
 (0)
X Tutup