Skip to content

Support for out-of-process iframes in Firefox#10707

Merged
michaelDCurran merged 2 commits into
nvaccess:masterfrom
jcsteh:fission
Feb 12, 2020
Merged

Support for out-of-process iframes in Firefox#10707
michaelDCurran merged 2 commits into
nvaccess:masterfrom
jcsteh:fission

Conversation

@jcsteh

@jcsteh jcsteh commented Jan 21, 2020

Copy link
Copy Markdown
Contributor

Link to issue number:

None. This supersedes an earlier attempt at this (#9672) that was reverted (#10538) due to severe performance problems.

Summary of the issue:

Firefox is adding support for out-of-process iframes; i.e. iframes rendered in a separate process to their embedder document. For an out-of-process iframe, the embedder has no knowledge of children in the embedded document and cannot communicate with the embedded document at all. This means that accChild for accessibles in the embedded document fails. This requires some changes to the gecko_ia2 virtual buffer.

Description of how this pull request fixes the issue:

In the gecko_ia2 vbuf:

  1. getNVDAObjectFromIdentifier: Use getNVDAObjectFromEvent instead of accChild on the document. This was changed some time ago to use accChild on the document in the theoretical hope that it might be slightly faster, since it doesn't need to go via the parent process. However, this was never proved to be a performance benefit in real terms. The root accessible is in the parent process and can fetch children in all content documents, so using AccessibleObjectFromEvent works as expected.
  2. __contains__: If accChild fails, get the embedder iframe and try accChild with the iframe's id. There can be nested out-of-process iframes, so we keep trying this until there are no more iframes in the hierarchy (or until we hit the buffer's root id). We cache iframes because walking iframes is expensive, and when trying to work out what TreeInterceptor an object belongs to, we'll need to query the iframes for each TreeInterceptor.

Testing performed:

  1. Loaded a document with two out-of-process iframes in one tab and a document with no iframes in another tab. In the Python console, saved the former document's TreeInterceptor as ti1 and the latter document's TreeInterceptor as ti2; e.g. ti1 = nav.treeInterceptor.
  2. Moved the navigator object to a node in the innermost iframe and pressed NVDA+control+z to take a console snapshot.
  3. Confirmed that nav in ti1 is True and nav in ti2 is False.
  4. Moved the navigator object to a node in the document with no iframes and pressed NVDA+control+z.
  5. Confirmed that nav in ti1 is False and nav in ti2 is True.

Also used a build with this change for a while doing some daily browsing with Gmail, GitHub, etc.

Finally, the performance problems that caused #9672 to be reverted occurred when there were several tabs loaded. I tried with 15 tabs open (focusing each to create a TreeInterceptor for it) and did not observe this performance degradation while browsing.

Known issues with pull request:

There will be some additional COM calls for objects in out-of-process iframes. However, the iframes for each object are cached while the object is alive, since getTreeInterceptor will call __contains__ on each TreeInterceptor until a match is found. There don't tend to be many levels of nested iframes, so filling the cache shouldn't be too expensive.

Other avenues explored:

See #9672.

Change log entry:

Changes:

- Support for out-of-process iframes in Mozilla Firefox.

…t instead of accChild on the document.

This was changed to use accChild on the document in the theoretical hope that it might be slightly faster, since it doesn't need to go via the parent process.
However, this was never proved to be a performance benefit in real terms.
In Firefox, when an iframe document is rendered in a separate process to its embedder, the embedder has no knowledge of children in the embedded document and cannot communicate with the embedded document at all.
This means that accChild for accessibles in the embedded document fails.
The root accessible is in the parent process and can fetch children in all content documents, so using AccessibleObjectFromEvent works as expected.
…me(s).

In Firefox, when an iframe/frame document is rendered in a separate process to its embedder, accChild for accessibles in the embedded document fails.
If this is the case, we can get the embedder frame and try accChild with the iframe's id.
There can be nested out-of-process frames, so we keep trying this until there are no more frames in the hierarchy (or until we hit the buffer's root id).
We cache frames because walking frames is expensive, and when trying to work out what TreeInterceptor an object belongs to, we'll need to query the frames for each TreeInterceptor.
@jcsteh jcsteh marked this pull request as ready for review February 10, 2020 04:14
@michaelDCurran michaelDCurran merged commit 93bd4ea into nvaccess:master Feb 12, 2020
@nvaccessAuto nvaccessAuto added this to the 2020.1 milestone Feb 12, 2020
@michaelDCurran

Copy link
Copy Markdown
Member

Just noting here (more for myself really) that the main point of the iframe cache is the situation where we need to check if the object is in many different treeInterceptors. I.e. the object will be reused in the cache throughout the execution of treeInterceptorHandler.getTreeInterceptor, and then will most likely disappear.

michaelDCurran added a commit that referenced this pull request Feb 12, 2020
@jcsteh jcsteh deleted the fission branch May 1, 2020 01:33
seanbudd pushed a commit that referenced this pull request Jun 27, 2024
…longer necessary. (#16746)

Reverts #10707.

Summary of the issue:
Firefox moved most iframes into different processes (AKA out-of-process iframes or project "Fission") in 2020. This necessitated some changes to NVDA because with Firefox's older multi-process architecture, objects in one process were unaware of objects in another. However, with the new "Cache the World" architecture released in Firefox 113 (just over a year ago in May 2023), this special handling is no longer necessary, since all objects are served from the parent process and the parent process is aware of all of them.

While removing this code likely doesn't have any discernible user benefit, I think it's worthwhile to remove unnecessary complexity.

There is no supported version of Firefox (even ESR) which depends on this code.

Description of user facing changes
None. There might be a slight performance benefit, but I doubt this is perceivable.

Description of development approach
Reverted #10707, adjusting for non-substantive changes that were made since #10707 was merged (code style, moved constants, etc.).

Note that this moves back to using accChild instead of getNVDAObjectFromEvent. At the time, there didn't appear to be a performance benefit to using accChild and using getNVDAObjectFromEvent made it easier to implement #10707. However, I have since then discovered (through Firefox profiling) that at least in-process, AccessibleObjectFromWindow can be rather slow relative to direct COM calls. This probably isn't noticeable for NVDA's use case, especially given that we're doing this across processes, but any performance boost is probably worthwhile here.

I didn't add a change log entry because there is no user visible change here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants