Chromium Code Reviews| 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 |