Skip to content

Remove from top layer synchronously for not connected elements#128

Merged
foolip merged 1 commit into
whatwg:masterfrom
dtapuska:alternate
Aug 29, 2018
Merged

Remove from top layer synchronously for not connected elements#128
foolip merged 1 commit into
whatwg:masterfrom
dtapuska:alternate

Conversation

@dtapuska

@dtapuska dtapuska commented May 18, 2018

Copy link
Copy Markdown
Contributor

If the fullscreen element is not connected anymore dispatch
event and unfullscreen the element right away.

This allows an element that is being removed to see that it isn't the
fullscreen element synchronously.


Preview | Diff

@dtapuska

Copy link
Copy Markdown
Contributor Author

@upsuper @foolip This is an alternate approach to (#126) to address issues in #102 that I think could be viable. Thoughts?

@foolip foolip left a comment

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.

I like this structure of a solution, having something funny happen when the fullscreen element is removed but not mucking with event timing or order in any other cases. Just some questions about the implications about the specifics.

Comment thread fullscreen.bs Outdated
<a>simple fullscreen document</a>, then set <var>doc</var> to <var>topLevelDoc</var> and
<var>resize</var> to true.

<li><p>If <var>doc</var>'s <a>fullscreen element</a> is not connected:

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread fullscreen.bs

<li><p>If <var>doc</var>'s <a>fullscreen element</a> is not connected:
<ol>
<li><p><a for=set>Append</a> (<code>fullscreenchange</code>, <var>doc</var>'s

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.

Exactly when this event will end up being fired won't be entirely reliable, it could be before or after the resize even depending on how fast the fullscreen transition is, but that's acceptable I think for this weird case. Did you look into firing the event in a task or microtask and which ways that is bad?

@dtapuska dtapuska May 22, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried firing it in a microtask and it seemed to work fine. However I kept it the same as all the other events. Because in the special cases (like firing fullscreenerror in Step 10.1 requesting fullscreen it still queues the event for at rAF time).

Comment thread fullscreen.bs Outdated
<a>fullscreen element</a>) to <var>doc</var>'s
<a>list of pending fullscreen events</a>.

<li><p><a lt="unfullscreen a document">Unfullscreen <var>doc</var></a>.

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.

Do funny things happen if we don't do this step?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes the fullscreenelement won't change synchronously (and that is the point of this change).

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.

document.fullscreenElement would change synchronously, because the element would be removed from top layer right after this code runs and before the element.remove() call returns.

@upsuper

upsuper commented May 23, 2018

Copy link
Copy Markdown
Member

There are still some funny edge cases with this approach especially regarding nested fullscreen.

For example, if the removed fullscreen element is an <iframe> element, its content would keep being in fullscreen state (it's not clear whether other approach can solve this natively but it might be something we can keep in mind?).

Also, if the document is a sub-document, and the <iframe> of its browsing context doesn't have iframe fullscreen flag set, the <iframe> should also exit fullscreen when the document gets unfullscreened.

@dtapuska

Copy link
Copy Markdown
Contributor Author

@upsuper Yes that is a problem how FullyExitFullscreen is defined. It doesn't recurse into iframes. If we want to keep this approach I suggest we take steps 3, 4, 5 from #126 but then it pretty much is #126

@foolip

foolip commented May 23, 2018

Copy link
Copy Markdown
Member

For example, if the removed fullscreen element is an <iframe> element, its content would keep being in fullscreen state (it's not clear whether other approach can solve this natively but it might be something we can keep in mind?).

Removing an iframe triggers https://html.spec.whatwg.org/multipage/window-object.html#a-browsing-context-is-discarded. If you have a handle to the document within you can still look at iframeDoc.fullscreenElement and see that it doesn't change. A test for this in the style of web-platform-tests/wpt#6302 should be possible. This is actually a funny thing that I don't think any solution to the "fullscreen element is removed" problem can get around. I think it already behaves as I described in Chromium.

Also, if the document is a sub-document, and the <iframe> of its browsing context doesn't have iframe fullscreen flag set, the <iframe> should also exit fullscreen when the document gets unfullscreened.

Yes. I think removing the "Unfullscreen doc" step and just continuing to run is the fix for this. Because document.fullscreenElement already changed, this can lead to exiting a step further than would have happened when calling document.exitFullscreen() (and not removing the fullscreen element) but this is similar to calling document.exitFullscreen() twice. The only way to avoid this is one of:

  1. Keeping track in the async part of "exit fullscreen" that the fullscreen element was removed and acting as if it were still in top layer at certain steps, to avoid exiting too much.
  2. Setting resize to true so that removing the fullscreen element always consistently exits fully.

I'd be OK with either just leaving it a bit odd or setting resize to true. Keeping track of more state doesn't sound great.

@dtapuska

Copy link
Copy Markdown
Contributor Author

Ok I've removed the Unfullscreen doc step and added back the remove top layer code from #102 to make this complete.

@foolip foolip left a comment

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.

Yes, this is the one! :)

@upsuper?

Comment thread fullscreen.bs

<li><p>If <var>doc</var>'s <a>fullscreen element</a> is not <a>connected</a>:
<ol>
<li><p><a for=set>Append</a> (<code>fullscreenchange</code>, <var>doc</var>'s

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.

Hmm, I realized one little wrinkle. We should probably call "unfullscreen an element" on the fullscreen element, so that the fullscreen flags are unset. Otherwise we'll be in a weird state where https://fullscreen.spec.whatwg.org/#css-pc-fullscreen continues to match.

That will mean that the other added "remove node from document’s top layer" will only clean up things other than fullscreen. That'll just have to be OK I think.

@upsuper

upsuper commented May 23, 2018

Copy link
Copy Markdown
Member

I don't think this is going to work... When you have two fullscreen elements in the top layer, and you remove one of them, you would end up making the browser window still in fullscreen, but the document has exited the fullscreen state.

@upsuper

upsuper commented May 23, 2018

Copy link
Copy Markdown
Member

So I still think it is easier to just fully exit fullscreen in this case. That would natively solve all the edge cases and leave a sane state just like when the user presses escape.

@upsuper

upsuper commented May 23, 2018

Copy link
Copy Markdown
Member

Note that, setting resize wouldn't work either. That way, you may end up having the document still in fullscreen state, but the window has been restored to normal state.

@foolip

foolip commented May 24, 2018

Copy link
Copy Markdown
Member

When you have two fullscreen elements in the top layer, and you remove one of them, you would end up making the browser window still in fullscreen, but the document has exited the fullscreen state.

This is a variation on the problem of calling document.exitFullscreen() twice, where neither call thinks it will end up fully exiting in their synchronous steps, but when the async steps of both have run the top layer is empty. The fix for this has to be in the async part of "exit fullscreen". Seems like there's no bug tracking this, and it's just a TODO in the Chromium code. (It just stays in fullscreen in a weird state.)

So I still think it is easier to just fully exit fullscreen in this case.

For some redefinition of "fully exit fullscreen" I think that would be fine, although if we fix the above problem that seems slightly nicer to me.

The main problem with #126 is poking at the state of other frames synchronously, and it can't be implemented exactly like that in Chromium. Doing #65 would resolve the problem, making "fully exit fullscreen" more async. As part of that we'd have to make sure that setting resize to true fully and correctly cleans up all state, even if we're in some odd state.

@upsuper

upsuper commented May 24, 2018

Copy link
Copy Markdown
Member

I would definitely be nice if we can fix the issue of double-calling to exitFullscreen, but leaving in such state isn't really the first thing I noticed.

With the double-calling exitFullscreen issue gets fixed, this approach is still a bit odd that: if you have two fullscreen elements and you remove one, you end up fully exit fullscreen, but if you have three, you end up being left in fullscreen. People (maybe library authors?) may start depending on removing element to fully unfullscreen (since in majority of cases it does), but then it breaks in some rare cases when there are more than three fullscreen elements.

The main problem with #126 is poking at the state of other frames synchronously, and it can't be implemented exactly like that in Chromium. Doing #65 would resolve the problem, making "fully exit fullscreen" more async.

It's not completely clear to me how #65 would make things better... Do you mean moving more stuff into the async part would make it easier to implement in Chrome? I guess I'm fine with something like, invoke fully exit fullscreen asynchronously when the element gets removed... Would that resolve your problem?

@dtapuska

Copy link
Copy Markdown
Contributor Author

It has been a while and I think last time @foolip indicated we probably needed a way to force a resize in a fullscreen exit. @upsuper does something like this make sense?

@dtapuska

Copy link
Copy Markdown
Contributor Author

@foolip ping

@foolip

foolip commented Aug 1, 2018

Copy link
Copy Markdown
Member

It's not completely clear to me how #65 would make things better... Do you mean moving more stuff into the async part would make it easier to implement in Chrome? I guess I'm fine with something like, invoke fully exit fullscreen asynchronously when the element gets removed... Would that resolve your problem?

@upsuper, yes, if we use "fully exit fullscreen" to handle removing the current fullscreen element, and if we want to guarantee that it really does leave the document in question with an empty top layer stack, or alternatively that we resize and empty the top layers of all documents, then "fully exist fullscreen" needs to have some flag to really guarantee that, much like what @dtapuska has pushed now, in the same vein as #65.

However, reading this thread again, and looking at the "double-calling exitFullscreen issue", I'd like to ask if we can separate these issues. We have a bunch of very intricate interactions between entering and exiting / full exiting fullscreen that don't quite make sense, and I think that making only "fully exit fullscreen" have a stronger guarantee isn't that helpful.

I would suggest, rather, that if we are really troubled by these interactions, that we make it explicit that only one request to enter or exit fullscreen can be in-flight at once, then we can stop worrying about these cases or multiple requests racing. Effectively, then, the fullscreen state is a global thing and the first request always wins. (Details to be worked out.)

@upsuper, do you think leaving this wart for now would be acceptable? It would amount to going back to the state of this PR at f59df4d.

@upsuper

upsuper commented Aug 2, 2018

Copy link
Copy Markdown
Member

The problem of f59df4d isn't really identical to double-calling exitFullscreen. It's something happening internally which has the same effect as double-calling at this moment. That means, adding some mechanism to make only one in-flight enter / exit change isn't going to help for that case.

But I think the discussion probably does go too far and I think it's fine that we resolve on doing f59df4d for now and try to figure out how to resolve its consequences.

@upsuper

upsuper commented Aug 2, 2018

Copy link
Copy Markdown
Member

I mean, try to figure out how to resolve its consequences later in separate issues.

@foolip

foolip commented Aug 9, 2018

Copy link
Copy Markdown
Member

@upsuper, yeah, you're right, while double document.exitFullscreen() is currently another way that one can end up in the asynchronous part of "exit fullscreen" with nothing in the top layer stack, fixing that would still leave this situation:

We're in nested fullscreen, two elements in the top layer stack. Removing the fullscreen element will not cause us to exit fullscreen, but still we'll end up in the asynchronous part of "exit fullscreen" removing the second element from the top layer.

@dtapuska, new idea for a fix. In the "If doc’s fullscreen element is not connected" condition, set a fullscreenElementWasConnected variable to false. In the async part (whether resize happened or not) just do nothing if that variable is false.

@foolip

foolip commented Aug 9, 2018

Copy link
Copy Markdown
Member

@dtapuska or, file an issue and let's merge this as is. Tests that could be adapted for this PR are in web-platform-tests/wpt#6302.

event and unfullscreen the element right away.

When an node is being remove synchronously remove it from the top layer.
@dtapuska

Copy link
Copy Markdown
Contributor Author

@foolip wpt tests already have landed for this. I've merged the pull requests into a single change and opened an issue for the two fullscreen elements in the top layer scenario. Please merge.

@foolip foolip merged commit 06c6e07 into whatwg:master Aug 29, 2018
@foolip

foolip commented Aug 29, 2018

Copy link
Copy Markdown
Member

Thanks @dtapuska!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants