Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: White frames appear when adding BrowserView with already loaded page #37201

Open
3 tasks done
Imperat opened this issue Feb 9, 2023 · 20 comments
Open
3 tasks done

Comments

@Imperat
Copy link
Contributor

Imperat commented Feb 9, 2023

Preflight Checklist

Electron Version

20.1.4

What operating system are you using?

macOS

Operating System Version

Ventura 13.2

What arch are you using?

x64

Last Known Working Electron version

No response

Expected Behavior

In my use case, I need to keep BrowserViews in memory and switch them.
To switch I use removeBrowserView and setBrowserView APIs like this:

    win.removeBrowserView(view1);
    win.setBrowserView(view2);

I expect that this switching will be experienced by users as tab switching in the browser. For example, if you open two tabs
https://www.electronjs.org/ & https://www.electronjs.org/docs/latest/api/app, and will start switching between them you will notice that the website header remains black (for this specific example with electronjs.rg).

In my use case, I need to add BrowserView with an already loaded page to the window. When I do this I am able to notice a white glitch even though I set another color as a background color for the window.
This bug is not reproducible if hardware acceleration is turned off. (app.disableHardwareAcceleration())

Actual Behavior

It works as desired on Windows 11.
On MacOS some white frames appear and make the user's experience less native.

Screen.Recording.2023-02-09.at.3.36.08.pm.mov

Can we get it fixed or give me suggestions on how I can perform a workaround, please?

Testcase Gist URL

https://gist.github.com/0c99927c913ac5971facd861dd656d8b

Additional Information

No response

@Prinzhorn
Copy link
Contributor

Prinzhorn commented Feb 9, 2023

Does addBrowserView + setTopBrowserView (alternatively move views out of bounds to hide them) work?

FWIW I don't see any flashing on Ubuntu. Also Electron 20 is EOL.

@Imperat
Copy link
Contributor Author

Imperat commented Feb 10, 2023

Hey @Prinzhorn
Thanks for your reply!
addBrowserView + setTopBrowserView works.
However, pages may have transparent background and it causes the pages to overlay each other:
Screenshot 2023-02-10 at 11 16 39 am

This is not something desired

@Prinzhorn
Copy link
Contributor

Either make it white via https://www.electronjs.org/docs/latest/api/browser-view#viewsetbackgroundcolorcolor-experimental or maybe try my other suggestion and translate the "invisible" views off-screen using setBounds. These are the same techniques you'd use in CSS for high-performance flicker-free switching of items (e.g. translate(x,y) them off-screen).

@codebytere codebytere added platform/macOS has-repro-gist Issue can be reproduced with code at https://gist.github.com/ 23-x-y component/BrowserView labels Feb 15, 2023
@Imperat
Copy link
Contributor Author

Imperat commented Mar 7, 2023

Hello,
I wanted to clarify the steps to reproduce via another fiddle: https://gist.github.com/Imperat/ad54907ca6e8d1167c5bde6a6bf389ac

Every time when I add a new browserView on top of another browserView the white glitch appears.
I want to fix it somehow without having all the browserView's attached. After I made some measures I found out the app consumes more resources when the window has attached multiple browserView's at the same time.

In my use case, we have a tab management feature, which does not look native when the user switches between tabs.

@Imperat
Copy link
Contributor Author

Imperat commented Mar 7, 2023

The way to reproduce it with one BrowserView instance.

// Modules to control application life and create native browser window
const {app, BrowserWindow, BrowserView} = require('electron')

app.whenReady().then(async () => {
  const win = new BrowserWindow({ 
    width: 800, 
    height: 600, 
    backgroundColor: 'black'
  })

  const view1 = new BrowserView()
  view1.setBackgroundColor('white');
  win.addBrowserView(view1);
  view1.setBounds({ x: 0, y: 0, width: 800, height: 600 })
  await view1.webContents.loadURL('https://electronjs.org/')

  setInterval(() => {
    win.removeBrowserView(view1);
    setTimeout(() => {
      win.addBrowserView(view1);
    }, 1000);
  }, 3000);
})

@Imperat Imperat changed the title [Bug]: White frames appear when switching between BrowserViews [Bug]: White frames appear when adding BrowserView with already loaded page Mar 7, 2023
@Imperat
Copy link
Contributor Author

Imperat commented Mar 7, 2023

I noticed that setTopBrowserView was added to Electron here by @stewartlord with the note:

Removing and re-adding a view also works but has the problem of introducing a noticeable flicker.

cc @stewartlord @codebytere Do you think we can fix it somehow in Electron? After a quick reading of Electron's source code, I think this is a Chromium bug. If you have any recommendations on what should be our next steps it will be very helpful!

@kevinlinv
Copy link
Contributor

I also found an error logged every time the view flickers on Fiddle.

[39915:0317/095700.282818:ERROR:shared_image_manager.cc(267)] SharedImageManager::ProduceOverlay: Trying to Produce a Overlay representation from a non-existent mailbox.
[39915:0317/095700.282829:ERROR:skia_output_device_buffer_queue.cc(354)] Invalid mailbox.

@kevinlinv
Copy link
Contributor

kevinlinv commented Mar 16, 2023

@Imperat

A trick to move the bounds around within a short timeout allows for a workaround for the code sample you added.

code snippet
// Modules to control application life and create native browser window
const {app, BrowserWindow, BrowserView} = require('electron')

app.whenReady().then(async () => {
  const win = new BrowserWindow({ 
    width: 800, 
    height: 600, 
    backgroundColor: 'black'
  })

  const view1 = new BrowserView()
  view1.setBackgroundColor('white');
  win.addBrowserView(view1);
  view1.setBounds({ x: 0, y: 0, width: 800, height: 600 })
  await view1.webContents.loadURL('https://electronjs.org/')

  setInterval(() => {
    win.removeBrowserView(view1);
    
    setTimeout(() => {
      win.addBrowserView(view1);
      view1.setBounds({ x: 800, y: 0, width: 800, height: 600 })
      setTimeout(() => view1.setBounds({ x: 0, y: 0, width: 800, height: 600 }), 20)
    }, 1000);
  }, 3000);
})

Perhaps there is an underlying race condition here?

@kevinlinv
Copy link
Contributor

Upon further testing, the workaround above only works on high-end Macs. Glitches will still appear on lower-end devices where the amount of resources is less. 😢

@github-actions
Copy link
Contributor

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

@github-actions github-actions bot added the stale label Jun 23, 2023
@Imperat
Copy link
Contributor Author

Imperat commented Jun 26, 2023

bump

@github-actions github-actions bot removed the stale label Jun 27, 2023
@Imperat
Copy link
Contributor Author

Imperat commented Jun 27, 2023

Hi team,
In an attempt to fix this issue I tried to develop a single API to replace browserView's.
Please, have a look at implementation of ReplaceBrowserView in PR from my fork

I use TakeFallbackContentFrom to avoid the glitch, but it doesn't seem enough.

I used this code to reproduce (it is compatible with my custom build and official one):

const {app, BrowserWindow, BrowserView } = require('electron')

const WIDTH = 300;
const HEIGHT = 200;
app.whenReady().then(() => {
  const win = new BrowserWindow({ width: WIDTH, height: HEIGHT })

  const view1 = new BrowserView()
  win.setBrowserView(view1)
  view1.setBounds({ x: 0, y: 0, width: WIDTH, height: HEIGHT })
  view1.webContents.loadURL('https://electronjs.org')

  const view2  = new BrowserView();
  win.setBrowserView(view2);
  view2.setBounds({ x: 0, y: 0, width: WIDTH, height: HEIGHT });
  view2.webContents.loadURL('https://www.electronjs.org');

  const show1 = () => {
    if (win.replaceBrowserView) {
      win.replaceBrowserView(view2, view1);
    } else {
      win.removeBrowserView(view1);
      win.setBrowserView(view2);
    }
  };

  const show2 = () => {
    if (win.replaceBrowserView) {
      win.replaceBrowserView(view1, view2);
    } else {
      win.removeBrowserView(view2);
      win.setBrowserView(view1);
    }
  };

  let check = true;
  setInterval(() => {
    check = !check;
    const func = check ? show2 : show1;
    func();
  }, 100);
})


app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})

Do you have any other recommendations or ideas?

@Imperat
Copy link
Contributor Author

Imperat commented Jun 27, 2023

Also, I tried to use a short delay (100ms) before showing new contents after it is attached.
I placed sources in this PR and it seems to work well.

However, it reminds me the same hack @kevinlinv described above. Probably it will not work in lower-end devices where the amount of resources is less.

I am interested if there is any other way to wait for content to be painted rather than use hard-coded delay? 🤔

@olegyadrov-bluescape
Copy link

Bump

@OldDream
Copy link

OldDream commented Nov 1, 2023

same problem here

@XiaoBaiClassmate
Copy link

same problem here.
Is there a solution?

@lauri865
Copy link

lauri865 commented Dec 6, 2023

Echo that. Makes the UI look very buggy, unfortunately. Haven't found any good workarounds yet.

@Imperat
Copy link
Contributor Author

Imperat commented Jan 22, 2024

To locate root reason for this bug I tried to dig into Chromium sources to see how tab switching implemented in browser itself, but I was not quite successful in this endeavor. If someone more experienced with Chromium codebase is reading this comment, please advice where to look for 🙏

@electron-issue-triage
Copy link

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

@Imperat
Copy link
Contributor Author

Imperat commented Apr 23, 2024

bump

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Status: Unsorted Items
Status: Unsorted Items
Status: 👍 Does Not Block Stable
Development

No branches or pull requests

8 participants