Demystifying FrameTree Concepts

What are Frame Trees?

There are two representations of FrameTrees used in rendering Web Pages.

These concepts are very similar, however on the content side a placeholder FrameTreeNode can be placed in the FrameTree to hold another frame tree. This FrameTreeNode's current RenderFrameHost will have a valid RenderFrameHostImpl::inner_tree_main_frame_tree_node_id frame tree node ID.

The renderer side (Blink) will have no notion of this placeholder in the frame tree and its frame tree appears as it would for the web exposed window.frames

Why do we nest frame trees?

Certain features that nest documents require a stronger boundary than what would be achievable with iframes. We want to prevent the exposure of information across this boundary. This may be for privacy reasons where we enforce communication restrictions between documents on the web (e.g. fenced frames). The boundary could also be between content on the web and parts of the user agent implemented with web technologies (e.g. chrome's PDF viewer, webview tag).

What are Outermost Main Frames?

Building on the concept above that a FrameTree can have an embedded FrameTree (and many nesting levels of them), there is the concept of the OutermostMainFrame. The OutermostMainFrame is the main frame (root) of a FrameTree that is not embedded in other FrameTrees. See footnote 1.

So that does mean there can be multiple main frames in a displayed tab to the user. For features like fencedframes the inner FrameTree has a main frame but it will not be an OutermostMainFrame.

To determine whether something is a main frame RenderFrameHost::GetParent is typically used. Likewise there is a RenderFrameHost::GetParentOrOuterDocument to determine if something is an OutermostMainFrame.

Example Frame Tree:
    A
     B (iframe)
     C (fenced frame - placeholder frame) [See footnote 2.]
      C* (main frame in fenced frame).

    C* GetParent returns null.
    C* GetParentOrOuterDocument returns A.
    C GetParent & GetParentOrOuterDocument returns A.
    B GetParent & GetParentOrOuterDocument returns A.
    A GetParent & GetParentOrOuterDocument returns nullptr.

Can I have multiple outermost main frames?

Prerender and back/forward cache are features where there can be other outermost main frame present in a WebContents.

What are Pages?

Pages can be an overloaded term so we will clarify what we mean by the class concepts:

The two usages are very similar, they effectively are an object representing the state of a FrameTree. Since frames can be hosted in different renderers (for isolation) there may be a number of Blink Page objects, one for each renderer that participates in the rendering of a single Page in content.

What is the Primary Page?

There is only ever one Primary Page for a given WebContents. The primary page is defined by the fact that the main frame is the OutermostMainFrame and being actively displayed in the tab.

The primary page can change over time (see WebContentsObserver::PrimaryPageChanged). The primary page can change when navigating, a Page is restored from the BackForwardCache or from the prendering pages.

Relationships between core classes in content/

A WebContents represents a tab. A WebContents owns a FrameTree, the “primary frame tree,” for what is being displayed in the tab. A WebContents may indirectly own additional FrameTrees for features such as prerendering.

A FrameTree consists of FrameTreeNodes. A FrameTreeNode contains a RenderFrameHost. FrameTreeNodes reflect the frame structure in the renderer. RenderFrameHosts represent documents loaded in a frame (roughly, see footnote 3). As a frame navigates its RenderFrameHost may change, but its FrameTreeNode stays the same.

In the case of nested frame trees, the RenderFrameHost corresponding to the hosting document owns the inner FrameTree (possibly through an intermediate object, as is the case for content::FencedFrame).

“MPArch”

“MPArch,” short for Multiple Page Architecture, refers to the name of the project that introduced the capability of having multiple FrameTrees in a single WebContents.

You may also see comments which describe features relying on multiple FrameTrees in terms of MPArch (e.g. “ignore navigations from MPArch pages”). These are in reference to “non-primary” frame trees as described above.

See the original design doc for further info.

Footnotes

1: GuestViews (embedding of a WebContents inside another WebContents) are considered embedded FrameTrees as well. However for consideration of OutermostMainFrames (ie. GetParentOrOuterDocument, Primary page) they do not escape the WebContents boundary because of the logical embedding boundary.

2: The placeholder RenderFrameHost is generally not exposed outside of the content boundary. Iteration APIs such as ForEachRenderFrameHost do not visit this node.

3: RenderFrameHost is not 1:1 with a document in the renderer. See RenderDocument.