1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
docs / frame_trees.md [blame]
# Demystifying FrameTree Concepts
## What are Frame Trees?
There are two representations of FrameTrees used in rendering Web Pages.
- Blink's [FrameTrees](../third_party/blink/renderer/core/page/frame_tree.h)
- Content's [FrameTrees](../content/browser/renderer_host/frame_tree.h)
These concepts are very similar, however on the content side a placeholder
[FrameTreeNode](../content/browser/renderer_host/frame_tree_node.h) 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](https://developer.mozilla.org/en-US/docs/Web/API/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.](#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:
- Blink's [Page](../third_party/blink/renderer/core/page/page.h)
- Content's [Page](../content/public/browser/page.h)
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](#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](https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing)
for further info.
## Footnotes
<a name="footnote_1"></a>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.
<a name="footnote_2"></a>2: The placeholder RenderFrameHost is generally not exposed outside
of the content boundary. Iteration APIs such as ForEachRenderFrameHost
do not visit this node.
<a name="footnote_3"></a>3: RenderFrameHost is not 1:1 with a document in the renderer.
See [RenderDocument](/docs/render_document.md).