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
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).
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.
Prerender and back/forward cache are features where there can be other outermost main frame present in a WebContents
.
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.
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.
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,” 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.
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.