OLD | NEW |
---|---|
(Empty) | |
1 # Tab Helpers | |
2 | |
3 The `content/` layer of Chromium has a class called `WebContents`, which is one | |
4 of the most basic building blocks of all of Chromium. This document describes | |
5 how `WebContents`es are used to build tabs in browser windows. | |
6 | |
7 [TOC] | |
8 | |
9 ## Introduction | |
10 | |
11 What is a "tab helper"? It is a `WebContentsObserver` owned by the `WebContents` | |
12 itself. Let's break that down. | |
13 | |
14 ## `WebContentsObserver` | |
15 | |
16 `WebContentsObserver` is a [simple interface](https://code.google.com/p/chromium /codesearch#chromium/src/content/public/browser/web_contents_observer.h&q=webcon tentsobserver) | |
17 that allows an object to observe events in the life of a `WebContents`. As an | |
18 example, if we look at the `TabStripModel`, there are times when it need to watc h | |
Bons
2015/08/31 18:50:52
this is over 80 char limit
Avi (use Gerrit)
2015/08/31 18:58:06
Done.
| |
19 out for WebContents being deleted. So it creates a [DeletionObserver](https://co de.google.com/p/chromium/codesearch#chromium/src/chrome/browser/ui/tabs/tab_stri p_model.cc&q=DeletionObserver). | |
20 The `DeletionObserver` overrides `WebContentsDestroyed()`, and when a | |
21 `WebContents` gets destroyed, the callback is called and the `DeletionObserver` | |
22 processes the message. Note that `DeletionObserver` is not owned by the | |
23 `WebContents`. It is owned indirectly by the `TabStripModel`. | |
24 | |
25 ## `SupportsUserData` and `WebContentsUserData` | |
26 | |
27 There is a mechanism used in Chromium called [`SupportsUserData`](https://code.g oogle.com/p/chromium/codesearch#chromium/src/base/supports_user_data.h&q=Support sUserData) | |
Bons
2015/08/31 18:50:52
place long links on their own line
There is a mec
Avi (use Gerrit)
2015/08/31 18:58:06
Done.
| |
28 that allows attaching of arbitrary objects to an object. The mechanism is | |
29 simple: host objects derive from `SupportsUserData`, and owned objects derive | |
30 from `SupportsUserData::Data`. There are three calls to attach and detach the | |
31 data. | |
32 | |
33 `WebContents` derives from `SupportsUserData`, so that mechanism works for | |
34 attaching objects to a `WebContents`, but the `SupportsUserData` mechanism is a | |
35 bit low-level. A higher level abstraction is [`WebContentsUserData`](https://cod e.google.com/p/chromium/codesearch#chromium/src/content/public/browser/web_conte nts_user_data.h&q=WebContentsUserData), | |
36 which is easy to derive from and has easy-to-use functionality in | |
37 `CreateForWebContents()` and `FromWebContents()`. | |
38 | |
39 ## Adding a feature to a browser tab | |
40 | |
41 Let's combine `WebContentsObserver` and `WebContentsUserData` together, to log | |
42 whenever the title of a tab changes. | |
43 | |
44 ``` | |
45 class TitleLoggerTabHelper | |
46 : public content::WebContentsObserver, | |
47 public content::WebContentsUserData<TitleLoggerTabHelper> { | |
48 public: | |
49 ~TitleLoggerTabHelper() override; | |
50 | |
51 // content::WebContentsObserver | |
52 void TitleWasSet(NavigationEntry* entry, bool explicit_set) override { | |
53 LOG(INFO) << "Title: " << entry->GetTitle(); | |
54 } | |
55 | |
56 private: | |
57 explicit TitleLoggerTabHelper(content::WebContents* web_contents); | |
58 friend class content::WebContentsUserData<TitleLoggerTabHelper>; | |
59 | |
60 DISALLOW_COPY_AND_ASSIGN(TitleLoggerTabHelper); | |
61 }; | |
62 | |
63 DEFINE_WEB_CONTENTS_USER_DATA_KEY(TitleLoggerTabHelper); | |
64 ``` | |
65 | |
66 We want each tab to have this `WebContentsObserver` attached to it, so that it | |
67 will properly handle the events it's looking for, and when the tab goes away, | |
68 then this tab helper will go away too. | |
69 | |
70 But how do you hook in to browser tab creation? How can we attach this tab | |
71 helper to the `WebContents`es that are used for the browser tabs? | |
72 | |
73 ## AttachTabHelpers | |
74 | |
75 There is a function called [`AttachTabHelpers()`](https://code.google.com/p/chro mium/codesearch#chromium/src/chrome/browser/ui/tab_helpers.cc&q=AttachTabHelpers ). | |
76 Whenever a `WebContents` is created for use as a browser tab, | |
77 `AttachTabHelpers()` is called. Every tab helper from around Chromium, | |
78 from ContentSettings to Favicons to History to Prefs, all take this opportunity | |
79 to hook into those `WebContents` used as tabs. | |
80 | |
81 If you are writing a feature that needs to deal with browser tabs, this is where | |
82 you go. Create a tab helper, and add it (in alphabetical order, please!) to | |
83 `AttachTabHelpers()`. Note, though, that you are _never_ allowed to call | |
84 `AttachTabHelpers()` yourself. `AttachTabHelpers()` is only for `WebContents` | |
85 that are in browser tabs, and all of those code paths are already written. | |
86 | |
87 ## Reusing tab helpers with non-browser tab `WebContents`es | |
88 | |
89 Sometimes it's useful to re-use tab helpers for `WebContents`es that aren't | |
90 browser tabs. For example, the Chrome Apps code wants to be able to print, and | |
91 wants to use the printing code that browser tabs use. So in | |
92 [`ChromeAppDelegate::InitWebContents()`](https://code.google.com/p/chromium/code search#chromium/src/chrome/browser/ui/apps/chrome_app_delegate.cc&q=ChromeAppDel egate::InitWebContents) | |
93 we see that whenever the Apps code creates a new `WebContents`, it attaches a | |
94 carefully-chosen subset of tab helpers, including two printing ones. | |
95 | |
96 You can do that too. If you are creating a `WebContents`, make a very deliberate | |
97 decision about which tab helpers you need. Chances are, you don't need them all; | |
98 you probably only need a handful. In fact, most tab helpers assume they are | |
99 attached to browser tabs, so only add the bare minimum. | |
100 | |
101 ## Not every `WebContents` has every tab helper | |
102 | |
103 The other consequence of this design is that you can't make the assumption that | |
104 an arbitrary `WebContents` will have an arbitrary tab helper. The | |
105 `WebContents`es used as browser tabs likely will have most tab helpers (though | |
106 not necessarily all of them!) but a `WebContents` only has a tab helper if it is | |
107 installed on it. | |
108 | |
109 The deeper (false and dangerous) assumption is that every `WebContents` is a | |
110 browser tab. Do not assume that either! | |
111 | |
112 If your code handles `WebContents`es, be aware of their source. It is extremely | |
113 rare to have to be able to handle arbitrary `WebContents`es. Know where they | |
114 come from and what tab helpers are on them, and you'll be fine. | |
OLD | NEW |