Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: chrome/browser/extensions/tab_helper.cc

Issue 10917026: Switch Extensions::TabHelper to use WebContents, WebContentsUserData. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase only Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/extensions/tab_helper.h ('k') | chrome/browser/sessions/session_service.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/tab_helper.h" 5 #include "chrome/browser/extensions/tab_helper.h"
6 6
7 #include "chrome/browser/extensions/app_notify_channel_ui.h"
7 #include "chrome/browser/extensions/crx_installer.h" 8 #include "chrome/browser/extensions/crx_installer.h"
8 #include "chrome/browser/extensions/app_notify_channel_ui.h"
9 #include "chrome/browser/extensions/extension_service.h" 9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_tab_util.h" 10 #include "chrome/browser/extensions/extension_tab_util.h"
11 #include "chrome/browser/extensions/page_action_controller.h" 11 #include "chrome/browser/extensions/page_action_controller.h"
12 #include "chrome/browser/extensions/script_badge_controller.h" 12 #include "chrome/browser/extensions/script_badge_controller.h"
13 #include "chrome/browser/extensions/webstore_inline_installer.h" 13 #include "chrome/browser/extensions/webstore_inline_installer.h"
14 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/sessions/session_id.h" 15 #include "chrome/browser/sessions/session_id.h"
16 #include "chrome/browser/sessions/session_tab_helper.h"
16 #include "chrome/browser/ui/browser_dialogs.h" 17 #include "chrome/browser/ui/browser_dialogs.h"
17 #include "chrome/browser/ui/tab_contents/tab_contents.h" 18 #include "chrome/browser/ui/tab_contents/tab_contents.h"
18 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
19 #include "chrome/browser/ui/web_applications/web_app_ui.h" 19 #include "chrome/browser/ui/web_applications/web_app_ui.h"
20 #include "chrome/browser/web_applications/web_app.h" 20 #include "chrome/browser/web_applications/web_app.h"
21 #include "chrome/common/chrome_notification_types.h" 21 #include "chrome/common/chrome_notification_types.h"
22 #include "chrome/common/extensions/extension_action.h" 22 #include "chrome/common/extensions/extension_action.h"
23 #include "chrome/common/extensions/extension_constants.h" 23 #include "chrome/common/extensions/extension_constants.h"
24 #include "chrome/common/extensions/extension_icon_set.h" 24 #include "chrome/common/extensions/extension_icon_set.h"
25 #include "chrome/common/extensions/extension_messages.h" 25 #include "chrome/common/extensions/extension_messages.h"
26 #include "chrome/common/extensions/extension_resource.h" 26 #include "chrome/common/extensions/extension_resource.h"
27 #include "chrome/common/extensions/extension_switch_utils.h" 27 #include "chrome/common/extensions/extension_switch_utils.h"
28 #include "content/public/browser/invalidate_type.h" 28 #include "content/public/browser/invalidate_type.h"
(...skipping 16 matching lines...) Expand all
45 using content::WebContents; 45 using content::WebContents;
46 46
47 namespace { 47 namespace {
48 48
49 const char kPermissionError[] = "permission_error"; 49 const char kPermissionError[] = "permission_error";
50 50
51 } // namespace 51 } // namespace
52 52
53 namespace extensions { 53 namespace extensions {
54 54
55 TabHelper::TabHelper(TabContents* tab_contents) 55 int TabHelper::kUserDataKey;
56 : content::WebContentsObserver(tab_contents->web_contents()), 56
57 TabHelper::TabHelper(content::WebContents* web_contents)
58 : content::WebContentsObserver(web_contents),
57 extension_app_(NULL), 59 extension_app_(NULL),
58 ALLOW_THIS_IN_INITIALIZER_LIST( 60 ALLOW_THIS_IN_INITIALIZER_LIST(
59 extension_function_dispatcher_(tab_contents->profile(), this)), 61 extension_function_dispatcher_(
62 Profile::FromBrowserContext(web_contents->GetBrowserContext()),
63 this)),
60 pending_web_app_action_(NONE), 64 pending_web_app_action_(NONE),
61 tab_contents_(tab_contents), 65 script_executor_(web_contents) {
62 script_executor_(tab_contents->web_contents()), 66 // The ActiveTabPermissionManager requires a session ID; ensure this
63 active_tab_permission_manager_( 67 // WebContents has one.
64 tab_contents->web_contents(), 68 SessionTabHelper::CreateForWebContents(web_contents);
65 SessionID::IdForTab(tab_contents->web_contents()), 69 active_tab_permission_manager_.reset(new ActiveTabPermissionManager(
66 tab_contents->profile()) { 70 web_contents,
71 SessionID::IdForTab(web_contents),
72 Profile::FromBrowserContext(web_contents->GetBrowserContext())));
67 if (switch_utils::AreScriptBadgesEnabled()) { 73 if (switch_utils::AreScriptBadgesEnabled()) {
68 location_bar_controller_.reset(new ScriptBadgeController( 74 location_bar_controller_.reset(
69 tab_contents->web_contents(), &script_executor_)); 75 new ScriptBadgeController(web_contents, &script_executor_));
70 } else { 76 } else {
71 location_bar_controller_.reset( 77 location_bar_controller_.reset(
72 new PageActionController(tab_contents->web_contents())); 78 new PageActionController(web_contents));
73 } 79 }
74 registrar_.Add(this, 80 registrar_.Add(this,
75 content::NOTIFICATION_LOAD_STOP, 81 content::NOTIFICATION_LOAD_STOP,
76 content::Source<NavigationController>( 82 content::Source<NavigationController>(
77 &tab_contents->web_contents()->GetController())); 83 &web_contents->GetController()));
78 } 84 }
79 85
80 TabHelper::~TabHelper() { 86 TabHelper::~TabHelper() {
81 } 87 }
82 88
83 void TabHelper::CopyStateFrom(const TabHelper& source) {
84 SetExtensionApp(source.extension_app());
85 extension_app_icon_ = source.extension_app_icon_;
86 }
87
88 void TabHelper::CreateApplicationShortcuts() { 89 void TabHelper::CreateApplicationShortcuts() {
89 DCHECK(CanCreateApplicationShortcuts()); 90 DCHECK(CanCreateApplicationShortcuts());
90 NavigationEntry* entry = 91 NavigationEntry* entry =
91 tab_contents_->web_contents()->GetController().GetLastCommittedEntry(); 92 web_contents()->GetController().GetLastCommittedEntry();
92 if (!entry) 93 if (!entry)
93 return; 94 return;
94 95
95 pending_web_app_action_ = CREATE_SHORTCUT; 96 pending_web_app_action_ = CREATE_SHORTCUT;
96 97
97 // Start fetching web app info for CreateApplicationShortcut dialog and show 98 // Start fetching web app info for CreateApplicationShortcut dialog and show
98 // the dialog when the data is available in OnDidGetApplicationInfo. 99 // the dialog when the data is available in OnDidGetApplicationInfo.
99 GetApplicationInfo(entry->GetPageID()); 100 GetApplicationInfo(entry->GetPageID());
100 } 101 }
101 102
102 bool TabHelper::CanCreateApplicationShortcuts() const { 103 bool TabHelper::CanCreateApplicationShortcuts() const {
103 #if defined(OS_MACOSX) 104 #if defined(OS_MACOSX)
104 return false; 105 return false;
105 #else 106 #else
106 return web_app::IsValidUrl(tab_contents_->web_contents()->GetURL()) && 107 return web_app::IsValidUrl(web_contents()->GetURL()) &&
107 pending_web_app_action_ == NONE; 108 pending_web_app_action_ == NONE;
108 #endif 109 #endif
109 } 110 }
110 111
111 void TabHelper::SetExtensionApp(const Extension* extension) { 112 void TabHelper::SetExtensionApp(const Extension* extension) {
112 DCHECK(!extension || extension->GetFullLaunchURL().is_valid()); 113 DCHECK(!extension || extension->GetFullLaunchURL().is_valid());
113 extension_app_ = extension; 114 extension_app_ = extension;
114 115
115 UpdateExtensionAppIcon(extension_app_); 116 UpdateExtensionAppIcon(extension_app_);
116 117
(...skipping 17 matching lines...) Expand all
134 135
135 SkBitmap* TabHelper::GetExtensionAppIcon() { 136 SkBitmap* TabHelper::GetExtensionAppIcon() {
136 if (extension_app_icon_.empty()) 137 if (extension_app_icon_.empty())
137 return NULL; 138 return NULL;
138 139
139 return &extension_app_icon_; 140 return &extension_app_icon_;
140 } 141 }
141 142
142 void TabHelper::RenderViewCreated(RenderViewHost* render_view_host) { 143 void TabHelper::RenderViewCreated(RenderViewHost* render_view_host) {
143 render_view_host->Send( 144 render_view_host->Send(
144 new ExtensionMsg_SetTabId( 145 new ExtensionMsg_SetTabId(render_view_host->GetRoutingID(),
145 render_view_host->GetRoutingID(), 146 SessionID::IdForTab(web_contents())));
146 SessionID::IdForTab(tab_contents_->web_contents())));
147 } 147 }
148 148
149 void TabHelper::DidNavigateMainFrame( 149 void TabHelper::DidNavigateMainFrame(
150 const content::LoadCommittedDetails& details, 150 const content::LoadCommittedDetails& details,
151 const content::FrameNavigateParams& params) { 151 const content::FrameNavigateParams& params) {
152 if (details.is_in_page) 152 if (details.is_in_page)
153 return; 153 return;
154 154
155 Profile* profile = 155 Profile* profile =
156 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 156 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
157 ExtensionService* service = profile->GetExtensionService(); 157 ExtensionService* service = profile->GetExtensionService();
158 if (!service) 158 if (!service)
159 return; 159 return;
160 160
161 for (ExtensionSet::const_iterator it = service->extensions()->begin(); 161 for (ExtensionSet::const_iterator it = service->extensions()->begin();
162 it != service->extensions()->end(); ++it) { 162 it != service->extensions()->end(); ++it) {
163 ExtensionAction* browser_action = (*it)->browser_action(); 163 ExtensionAction* browser_action = (*it)->browser_action();
164 if (browser_action) { 164 if (browser_action) {
165 browser_action->ClearAllValuesForTab( 165 browser_action->ClearAllValuesForTab(SessionID::IdForTab(web_contents()));
166 SessionID::IdForTab(tab_contents_->web_contents()));
167 content::NotificationService::current()->Notify( 166 content::NotificationService::current()->Notify(
168 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, 167 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
169 content::Source<ExtensionAction>(browser_action), 168 content::Source<ExtensionAction>(browser_action),
170 content::NotificationService::NoDetails()); 169 content::NotificationService::NoDetails());
171 } 170 }
172 } 171 }
173 } 172 }
174 173
175 bool TabHelper::OnMessageReceived(const IPC::Message& message) { 174 bool TabHelper::OnMessageReceived(const IPC::Message& message) {
176 bool handled = true; 175 bool handled = true;
177 IPC_BEGIN_MESSAGE_MAP(TabHelper, message) 176 IPC_BEGIN_MESSAGE_MAP(TabHelper, message)
178 IPC_MESSAGE_HANDLER(ExtensionHostMsg_DidGetApplicationInfo, 177 IPC_MESSAGE_HANDLER(ExtensionHostMsg_DidGetApplicationInfo,
179 OnDidGetApplicationInfo) 178 OnDidGetApplicationInfo)
180 IPC_MESSAGE_HANDLER(ExtensionHostMsg_InstallApplication, 179 IPC_MESSAGE_HANDLER(ExtensionHostMsg_InstallApplication,
181 OnInstallApplication) 180 OnInstallApplication)
182 IPC_MESSAGE_HANDLER(ExtensionHostMsg_InlineWebstoreInstall, 181 IPC_MESSAGE_HANDLER(ExtensionHostMsg_InlineWebstoreInstall,
183 OnInlineWebstoreInstall) 182 OnInlineWebstoreInstall)
184 IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppNotifyChannel, 183 IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppNotifyChannel,
185 OnGetAppNotifyChannel) 184 OnGetAppNotifyChannel)
186 IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppInstallState, 185 IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppInstallState,
187 OnGetAppInstallState); 186 OnGetAppInstallState);
188 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) 187 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
189 IPC_MESSAGE_UNHANDLED(handled = false) 188 IPC_MESSAGE_UNHANDLED(handled = false)
190 IPC_END_MESSAGE_MAP() 189 IPC_END_MESSAGE_MAP()
191 return handled; 190 return handled;
192 } 191 }
193 192
193 void TabHelper::DidCloneToNewWebContents(WebContents* old_web_contents,
194 WebContents* new_web_contents) {
195 // When the WebContents that this is attached to is cloned, give the new clone
196 // a TabHelper and copy state over.
197 CreateForWebContents(new_web_contents);
198 TabHelper* new_helper = FromWebContents(new_web_contents);
199
200 new_helper->SetExtensionApp(extension_app());
201 new_helper->extension_app_icon_ = extension_app_icon_;
202 }
203
204
194 void TabHelper::OnDidGetApplicationInfo(int32 page_id, 205 void TabHelper::OnDidGetApplicationInfo(int32 page_id,
195 const WebApplicationInfo& info) { 206 const WebApplicationInfo& info) {
196 // Android does not implement BrowserWindow. 207 // Android does not implement BrowserWindow.
197 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) 208 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
198 web_app_info_ = info; 209 web_app_info_ = info;
199 210
200 NavigationEntry* entry = 211 NavigationEntry* entry =
201 tab_contents_->web_contents()->GetController().GetLastCommittedEntry(); 212 web_contents()->GetController().GetLastCommittedEntry();
202 if (!entry || (entry->GetPageID() != page_id)) 213 if (!entry || (entry->GetPageID() != page_id))
203 return; 214 return;
204 215
216 TabContents* tab_contents = TabContents::FromWebContents(web_contents());
205 switch (pending_web_app_action_) { 217 switch (pending_web_app_action_) {
206 case CREATE_SHORTCUT: { 218 case CREATE_SHORTCUT: {
207 chrome::ShowCreateWebAppShortcutsDialog( 219 chrome::ShowCreateWebAppShortcutsDialog(
208 tab_contents_->web_contents()->GetView()->GetTopLevelNativeWindow(), 220 web_contents()->GetView()->GetTopLevelNativeWindow(),
209 tab_contents_); 221 tab_contents);
210 break; 222 break;
211 } 223 }
212 case UPDATE_SHORTCUT: { 224 case UPDATE_SHORTCUT: {
213 web_app::UpdateShortcutForTabContents(tab_contents_); 225 web_app::UpdateShortcutForTabContents(tab_contents);
214 break; 226 break;
215 } 227 }
216 default: 228 default:
217 NOTREACHED(); 229 NOTREACHED();
218 break; 230 break;
219 } 231 }
220 232
221 pending_web_app_action_ = NONE; 233 pending_web_app_action_ = NONE;
222 #endif 234 #endif
223 } 235 }
224 236
225 void TabHelper::OnInstallApplication(const WebApplicationInfo& info) { 237 void TabHelper::OnInstallApplication(const WebApplicationInfo& info) {
226 Profile* profile = 238 Profile* profile =
227 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 239 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
228 ExtensionService* extension_service = profile->GetExtensionService(); 240 ExtensionService* extension_service = profile->GetExtensionService();
229 if (!extension_service) 241 if (!extension_service)
230 return; 242 return;
231 243
232 ExtensionInstallPrompt* prompt = NULL; 244 ExtensionInstallPrompt* prompt = NULL;
233 if (extension_service->show_extensions_prompts()) { 245 if (extension_service->show_extensions_prompts()) {
234 gfx::NativeWindow parent = 246 gfx::NativeWindow parent =
235 tab_contents_->web_contents()->GetView()->GetTopLevelNativeWindow(); 247 web_contents()->GetView()->GetTopLevelNativeWindow();
236 prompt = new ExtensionInstallPrompt(parent, 248 Profile* profile =
237 tab_contents_->web_contents(), 249 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
238 tab_contents_->profile()); 250 prompt = new ExtensionInstallPrompt(parent, web_contents(), profile);
239 } 251 }
240 scoped_refptr<CrxInstaller> installer( 252 scoped_refptr<CrxInstaller> installer(
241 CrxInstaller::Create(extension_service, prompt)); 253 CrxInstaller::Create(extension_service, prompt));
242 installer->InstallWebApp(info); 254 installer->InstallWebApp(info);
243 } 255 }
244 256
245 void TabHelper::OnInlineWebstoreInstall( 257 void TabHelper::OnInlineWebstoreInstall(
246 int install_id, 258 int install_id,
247 int return_route_id, 259 int return_route_id,
248 const std::string& webstore_item_id, 260 const std::string& webstore_item_id,
(...skipping 10 matching lines...) Expand all
259 271
260 void TabHelper::OnGetAppNotifyChannel(const GURL& requestor_url, 272 void TabHelper::OnGetAppNotifyChannel(const GURL& requestor_url,
261 const std::string& client_id, 273 const std::string& client_id,
262 int return_route_id, 274 int return_route_id,
263 int callback_id) { 275 int callback_id) {
264 // Check for permission first. 276 // Check for permission first.
265 Profile* profile = 277 Profile* profile =
266 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 278 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
267 ExtensionService* extension_service = profile->GetExtensionService(); 279 ExtensionService* extension_service = profile->GetExtensionService();
268 ProcessMap* process_map = extension_service->process_map(); 280 ProcessMap* process_map = extension_service->process_map();
269 content::RenderProcessHost* process = 281 content::RenderProcessHost* process = web_contents()->GetRenderProcessHost();
270 tab_contents()->web_contents()->GetRenderProcessHost();
271 const Extension* extension = 282 const Extension* extension =
272 extension_service->GetInstalledApp(requestor_url); 283 extension_service->GetInstalledApp(requestor_url);
273 284
274 std::string error; 285 std::string error;
275 if (!extension || 286 if (!extension ||
276 !extension->HasAPIPermission(APIPermission::kAppNotifications) || 287 !extension->HasAPIPermission(APIPermission::kAppNotifications) ||
277 !process_map->Contains(extension->id(), process->GetID())) 288 !process_map->Contains(extension->id(), process->GetID()))
278 error = kPermissionError; 289 error = kPermissionError;
279 290
280 // Make sure the extension can cross to the main profile, if called from an 291 // Make sure the extension can cross to the main profile, if called from an
281 // an incognito window. 292 // an incognito window.
282 if (profile->IsOffTheRecord() && 293 if (profile->IsOffTheRecord() &&
283 !extension_service->CanCrossIncognito(extension)) 294 !extension_service->CanCrossIncognito(extension))
284 error = extension_misc::kAppNotificationsIncognitoError; 295 error = extension_misc::kAppNotificationsIncognitoError;
285 296
286 if (!error.empty()) { 297 if (!error.empty()) {
287 Send(new ExtensionMsg_GetAppNotifyChannelResponse( 298 Send(new ExtensionMsg_GetAppNotifyChannelResponse(
288 return_route_id, "", error, callback_id)); 299 return_route_id, "", error, callback_id));
289 return; 300 return;
290 } 301 }
291 302
303 TabContents* tab_contents = TabContents::FromWebContents(web_contents());
292 AppNotifyChannelUI* ui = AppNotifyChannelUI::Create( 304 AppNotifyChannelUI* ui = AppNotifyChannelUI::Create(
293 profile, tab_contents(), extension->name(), 305 profile, tab_contents, extension->name(),
294 AppNotifyChannelUI::NOTIFICATION_INFOBAR); 306 AppNotifyChannelUI::NOTIFICATION_INFOBAR);
295 307
296 scoped_refptr<AppNotifyChannelSetup> channel_setup( 308 scoped_refptr<AppNotifyChannelSetup> channel_setup(
297 new AppNotifyChannelSetup(profile, 309 new AppNotifyChannelSetup(profile,
298 extension->id(), 310 extension->id(),
299 client_id, 311 client_id,
300 requestor_url, 312 requestor_url,
301 return_route_id, 313 return_route_id,
302 callback_id, 314 callback_id,
303 ui, 315 ui,
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 void TabHelper::GetApplicationInfo(int32 page_id) { 434 void TabHelper::GetApplicationInfo(int32 page_id) {
423 Send(new ExtensionMsg_GetApplicationInfo(routing_id(), page_id)); 435 Send(new ExtensionMsg_GetApplicationInfo(routing_id(), page_id));
424 } 436 }
425 437
426 void TabHelper::Observe(int type, 438 void TabHelper::Observe(int type,
427 const content::NotificationSource& source, 439 const content::NotificationSource& source,
428 const content::NotificationDetails& details) { 440 const content::NotificationDetails& details) {
429 DCHECK(type == content::NOTIFICATION_LOAD_STOP); 441 DCHECK(type == content::NOTIFICATION_LOAD_STOP);
430 const NavigationController& controller = 442 const NavigationController& controller =
431 *content::Source<NavigationController>(source).ptr(); 443 *content::Source<NavigationController>(source).ptr();
432 DCHECK_EQ(controller.GetWebContents(), tab_contents_->web_contents()); 444 DCHECK_EQ(controller.GetWebContents(), web_contents());
433 445
434 if (pending_web_app_action_ == UPDATE_SHORTCUT) { 446 if (pending_web_app_action_ == UPDATE_SHORTCUT) {
435 // Schedule a shortcut update when web application info is available if 447 // Schedule a shortcut update when web application info is available if
436 // last committed entry is not NULL. Last committed entry could be NULL 448 // last committed entry is not NULL. Last committed entry could be NULL
437 // when an interstitial page is injected (e.g. bad https certificate, 449 // when an interstitial page is injected (e.g. bad https certificate,
438 // malware site etc). When this happens, we abort the shortcut update. 450 // malware site etc). When this happens, we abort the shortcut update.
439 NavigationEntry* entry = controller.GetLastCommittedEntry(); 451 NavigationEntry* entry = controller.GetLastCommittedEntry();
440 if (entry) 452 if (entry)
441 GetApplicationInfo(entry->GetPageID()); 453 GetApplicationInfo(entry->GetPageID());
442 else 454 else
443 pending_web_app_action_ = NONE; 455 pending_web_app_action_ = NONE;
444 } 456 }
445 } 457 }
446 458
447 } // namespace extensions 459 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/tab_helper.h ('k') | chrome/browser/sessions/session_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698