Dave Tapuska | 9de4102 | 2022-05-27 19:33:52 | [diff] [blame] | 1 | # Demystifying FrameTree Concepts |
| 2 | |
| 3 | ## What are Frame Trees? |
| 4 | |
| 5 | There are two representations of FrameTrees used in rendering Web Pages. |
| 6 | - Blink's [FrameTrees](../third_party/blink/renderer/core/page/frame_tree.h) |
| 7 | - Content's [FrameTrees](../content/browser/renderer_host/frame_tree.h) |
| 8 | |
| 9 | These concepts are very similar, however on the content side a placeholder |
| 10 | [FrameTreeNode](../content/browser/renderer_host/frame_tree_node.h) can |
| 11 | be placed in the FrameTree to hold another frame tree. This `FrameTreeNode`'s |
| 12 | current RenderFrameHost will have a valid |
| 13 | `RenderFrameHostImpl::inner_tree_main_frame_tree_node_id` frame tree node |
| 14 | ID. |
| 15 | |
| 16 | The renderer side (Blink) will have no notion of this placeholder in the |
| 17 | frame tree and its frame tree appears as it would for the web exposed |
| 18 | [window.frames](https://developer.mozilla.org/en-US/docs/Web/API/Window/frames) |
| 19 | |
Kevin McNee | 8ecc37e | 2022-06-24 19:48:51 | [diff] [blame] | 20 | ## Why do we nest frame trees? |
| 21 | |
| 22 | Certain features that nest documents require a stronger boundary than what would |
| 23 | be achievable with iframes. We want to prevent the exposure of information |
| 24 | across this boundary. This may be for privacy reasons where we enforce |
| 25 | communication restrictions between documents on the web (e.g. fenced frames). |
| 26 | The boundary could also be between content on the web and parts of the user |
| 27 | agent implemented with web technologies (e.g. chrome's PDF viewer, webview tag). |
| 28 | |
Dave Tapuska | 9de4102 | 2022-05-27 19:33:52 | [diff] [blame] | 29 | ## What are Outermost Main Frames? |
| 30 | |
| 31 | Building on the concept above that a `FrameTree` can have an embedded |
| 32 | `FrameTree` (and many nesting levels of them), there is the concept of |
| 33 | the `OutermostMainFrame`. The OutermostMainFrame is the main frame (root) |
Dave Tapuska | 8ff7ac8a | 2022-06-07 13:51:29 | [diff] [blame] | 34 | of a FrameTree that is not embedded in other FrameTrees. |
| 35 | [See footnote 1.](#footnote_1) |
Dave Tapuska | 9de4102 | 2022-05-27 19:33:52 | [diff] [blame] | 36 | |
| 37 | So that does mean there can be __multiple main frames__ in a displayed |
| 38 | tab to the user. For features like `fencedframes` the inner `FrameTree` |
| 39 | has a main frame but it will not be an `OutermostMainFrame`. |
| 40 | |
| 41 | To determine whether something is a main frame `RenderFrameHost::GetParent` |
| 42 | is typically used. Likewise there is a `RenderFrameHost::GetParentOrOuterDocument` to determine if something is an `OutermostMainFrame`. |
| 43 | |
Dave Tapuska | 8ff7ac8a | 2022-06-07 13:51:29 | [diff] [blame] | 44 | ``` |
Dave Tapuska | 9de4102 | 2022-05-27 19:33:52 | [diff] [blame] | 45 | Example Frame Tree: |
| 46 | A |
| 47 | B (iframe) |
Dave Tapuska | 8ff7ac8a | 2022-06-07 13:51:29 | [diff] [blame] | 48 | C (fenced frame - placeholder frame) [See footnote 2.] |
Dave Tapuska | 9de4102 | 2022-05-27 19:33:52 | [diff] [blame] | 49 | C* (main frame in fenced frame). |
| 50 | |
| 51 | C* GetParent returns null. |
| 52 | C* GetParentOrOuterDocument returns A. |
| 53 | C GetParent & GetParentOrOuterDocument returns A. |
| 54 | B GetParent & GetParentOrOuterDocument returns A. |
| 55 | A GetParent & GetParentOrOuterDocument returns nullptr. |
Dave Tapuska | 8ff7ac8a | 2022-06-07 13:51:29 | [diff] [blame] | 56 | ``` |
Dave Tapuska | 9de4102 | 2022-05-27 19:33:52 | [diff] [blame] | 57 | |
| 58 | ## Can I have multiple outermost main frames? |
| 59 | |
| 60 | Prerender and back/forward cache are features where there can be |
| 61 | other outermost main frame present in a `WebContents`. |
| 62 | |
| 63 | ## What are Pages? |
| 64 | |
| 65 | Pages can be an overloaded term so we will clarify what we mean by the |
| 66 | class concepts: |
| 67 | - Blink's [Page](../third_party/blink/renderer/core/page/page.h) |
| 68 | - Content's [Page](../content/public/browser/page.h) |
| 69 | |
| 70 | The two usages are very similar, they effectively are an object representing |
| 71 | the state of a `FrameTree`. Since frames can be hosted in different renderers |
| 72 | (for isolation) there may be a number of Blink `Page` objects, one for each |
| 73 | renderer that participates in the rendering of a single `Page` in content. |
| 74 | |
| 75 | ## What is the Primary Page? |
| 76 | |
| 77 | There is only ever one Primary Page for a given `WebContents`. The primary |
| 78 | page is defined by the fact that the main frame is the `OutermostMainFrame` |
| 79 | and being actively displayed in the tab. |
| 80 | |
| 81 | The primary page can change over time (see |
| 82 | `WebContentsObserver::PrimaryPageChanged`). The primary page can change when |
| 83 | navigating, a `Page` is restored from the `BackForwardCache` or from the |
| 84 | prendering pages. |
| 85 | |
Kevin McNee | 8ecc37e | 2022-06-24 19:48:51 | [diff] [blame] | 86 | ## Relationships between core classes in content/ |
| 87 | |
| 88 | A WebContents represents a tab. A WebContents owns a FrameTree, the "primary |
| 89 | frame tree," for what is being displayed in the tab. A WebContents may |
| 90 | indirectly own additional FrameTrees for features such as prerendering. |
| 91 | |
| 92 | A FrameTree consists of FrameTreeNodes. A FrameTreeNode contains a |
| 93 | RenderFrameHost. FrameTreeNodes reflect the frame structure in the renderer. |
| 94 | RenderFrameHosts represent documents loaded in a frame (roughly, |
| 95 | [see footnote 3](#footnote_3)). As a frame navigates its RenderFrameHost may |
| 96 | change, but its FrameTreeNode stays the same. |
| 97 | |
| 98 | In the case of nested frame trees, the RenderFrameHost corresponding to the |
| 99 | hosting document owns the inner FrameTree (possibly through an intermediate |
| 100 | object, as is the case for content::FencedFrame). |
| 101 | |
Kevin McNee | 88bf224 | 2022-11-23 00:27:34 | [diff] [blame] | 102 | ## "MPArch" |
| 103 | |
| 104 | "MPArch," short for Multiple Page Architecture, refers to the name of the |
| 105 | project that introduced the capability of having multiple FrameTrees in a |
| 106 | single WebContents. |
| 107 | |
| 108 | You may also see comments which describe features relying on multiple FrameTrees |
| 109 | in terms of MPArch (e.g. "ignore navigations from MPArch pages"). These are in |
| 110 | reference to "non-primary" frame trees as described above. |
| 111 | |
| 112 | See the original [design doc](https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing) |
| 113 | for further info. |
| 114 | |
Dave Tapuska | 8ff7ac8a | 2022-06-07 13:51:29 | [diff] [blame] | 115 | ## Footnotes |
| 116 | |
| 117 | <a name="footnote_1"></a>1: GuestViews (embedding of a WebContents inside another WebContents) are |
Dave Tapuska | 9de4102 | 2022-05-27 19:33:52 | [diff] [blame] | 118 | considered embedded FrameTrees as well. However for consideration of |
| 119 | OutermostMainFrames (ie. GetParentOrOuterDocument, Primary page) they do not |
| 120 | escape the WebContents boundary because of the logical embedding boundary. |
| 121 | |
Dave Tapuska | 8ff7ac8a | 2022-06-07 13:51:29 | [diff] [blame] | 122 | <a name="footnote_2"></a>2: The placeholder RenderFrameHost is generally not exposed outside |
Dave Tapuska | 9de4102 | 2022-05-27 19:33:52 | [diff] [blame] | 123 | of the content boundary. Iteration APIs such as ForEachRenderFrameHost |
| 124 | do not visit this node. |
Kevin McNee | 8ecc37e | 2022-06-24 19:48:51 | [diff] [blame] | 125 | |
| 126 | <a name="footnote_3"></a>3: RenderFrameHost is not 1:1 with a document in the renderer. |
| 127 | See [RenderDocument](/docs/render_document.md). |