Move extension_messages.h to extensions/common.
[chromium-blink-merge.git] / chrome / browser / extensions / tab_helper.cc
blob5bc94afe0520ab2c193b417855d8b0ce3a3df568
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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/tab_helper.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/extensions/activity_log/activity_log.h"
13 #include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
14 #include "chrome/browser/extensions/api/declarative_content/content_rules_registry.h"
15 #include "chrome/browser/extensions/crx_installer.h"
16 #include "chrome/browser/extensions/error_console/error_console.h"
17 #include "chrome/browser/extensions/extension_action.h"
18 #include "chrome/browser/extensions/extension_action_manager.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/extensions/extension_tab_util.h"
21 #include "chrome/browser/extensions/favicon_downloader.h"
22 #include "chrome/browser/extensions/image_loader.h"
23 #include "chrome/browser/extensions/page_action_controller.h"
24 #include "chrome/browser/extensions/script_executor.h"
25 #include "chrome/browser/extensions/webstore_inline_installer.h"
26 #include "chrome/browser/extensions/webstore_inline_installer_factory.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/sessions/session_id.h"
29 #include "chrome/browser/sessions/session_tab_helper.h"
30 #include "chrome/browser/shell_integration.h"
31 #include "chrome/browser/ui/browser_commands.h"
32 #include "chrome/browser/ui/browser_dialogs.h"
33 #include "chrome/browser/ui/browser_finder.h"
34 #include "chrome/browser/ui/browser_window.h"
35 #include "chrome/browser/ui/host_desktop.h"
36 #include "chrome/browser/ui/web_applications/web_app_ui.h"
37 #include "chrome/browser/web_applications/web_app.h"
38 #include "chrome/common/chrome_switches.h"
39 #include "chrome/common/extensions/chrome_extension_messages.h"
40 #include "chrome/common/extensions/extension_constants.h"
41 #include "chrome/common/extensions/extension_icon_set.h"
42 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
43 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
44 #include "chrome/common/render_messages.h"
45 #include "chrome/common/url_constants.h"
46 #include "content/public/browser/invalidate_type.h"
47 #include "content/public/browser/navigation_controller.h"
48 #include "content/public/browser/navigation_details.h"
49 #include "content/public/browser/navigation_entry.h"
50 #include "content/public/browser/notification_service.h"
51 #include "content/public/browser/notification_source.h"
52 #include "content/public/browser/notification_types.h"
53 #include "content/public/browser/render_process_host.h"
54 #include "content/public/browser/render_view_host.h"
55 #include "content/public/browser/render_widget_host_view.h"
56 #include "content/public/browser/web_contents.h"
57 #include "content/public/browser/web_contents_view.h"
58 #include "content/public/common/frame_navigate_params.h"
59 #include "extensions/browser/extension_error.h"
60 #include "extensions/browser/extension_registry.h"
61 #include "extensions/browser/extension_system.h"
62 #include "extensions/common/extension.h"
63 #include "extensions/common/extension_messages.h"
64 #include "extensions/common/extension_resource.h"
65 #include "extensions/common/extension_urls.h"
66 #include "extensions/common/feature_switch.h"
67 #include "skia/ext/image_operations.h"
68 #include "skia/ext/platform_canvas.h"
69 #include "ui/gfx/color_analysis.h"
70 #include "ui/gfx/image/image.h"
72 #if defined(OS_CHROMEOS)
73 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
74 #endif
76 using content::NavigationController;
77 using content::NavigationEntry;
78 using content::RenderViewHost;
79 using content::WebContents;
81 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::TabHelper);
83 namespace extensions {
85 TabHelper::ScriptExecutionObserver::ScriptExecutionObserver(
86 TabHelper* tab_helper)
87 : tab_helper_(tab_helper) {
88 tab_helper_->AddScriptExecutionObserver(this);
91 TabHelper::ScriptExecutionObserver::ScriptExecutionObserver()
92 : tab_helper_(NULL) {
95 TabHelper::ScriptExecutionObserver::~ScriptExecutionObserver() {
96 if (tab_helper_)
97 tab_helper_->RemoveScriptExecutionObserver(this);
100 // static
101 std::map<int, SkBitmap> TabHelper::ConstrainBitmapsToSizes(
102 const std::vector<SkBitmap>& bitmaps,
103 const std::set<int>& sizes) {
104 std::map<int, SkBitmap> output_bitmaps;
105 std::map<int, SkBitmap> ordered_bitmaps;
106 for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin();
107 it != bitmaps.end(); ++it) {
108 DCHECK(it->width() == it->height());
109 ordered_bitmaps[it->width()] = *it;
112 std::set<int>::const_iterator sizes_it = sizes.begin();
113 std::map<int, SkBitmap>::const_iterator bitmaps_it = ordered_bitmaps.begin();
114 while (sizes_it != sizes.end() && bitmaps_it != ordered_bitmaps.end()) {
115 int size = *sizes_it;
116 // Find the closest not-smaller bitmap.
117 bitmaps_it = ordered_bitmaps.lower_bound(size);
118 ++sizes_it;
119 // Ensure the bitmap is valid and smaller than the next allowed size.
120 if (bitmaps_it != ordered_bitmaps.end() &&
121 (sizes_it == sizes.end() || bitmaps_it->second.width() < *sizes_it)) {
122 // Resize the bitmap if it does not exactly match the desired size.
123 output_bitmaps[size] = bitmaps_it->second.width() == size
124 ? bitmaps_it->second
125 : skia::ImageOperations::Resize(
126 bitmaps_it->second, skia::ImageOperations::RESIZE_LANCZOS3,
127 size, size);
130 return output_bitmaps;
133 // static
134 void TabHelper::GenerateContainerIcon(std::map<int, SkBitmap>* bitmaps,
135 int output_size) {
136 std::map<int, SkBitmap>::const_iterator it =
137 bitmaps->lower_bound(output_size);
138 // Do nothing if there is no icon smaller than the desired size or there is
139 // already an icon of |output_size|.
140 if (it == bitmaps->begin() || bitmaps->count(output_size))
141 return;
143 --it;
144 // This is the biggest icon smaller than |output_size|.
145 const SkBitmap& base_icon = it->second;
147 const size_t kBorderRadius = 5;
148 const size_t kColorStripHeight = 3;
149 const SkColor kBorderColor = 0xFFD5D5D5;
150 const SkColor kBackgroundColor = 0xFFFFFFFF;
152 // Create a separate canvas for the color strip.
153 SkBitmap color_strip_bitmap;
154 color_strip_bitmap.allocN32Pixels(output_size, output_size);
155 SkCanvas color_strip_canvas(color_strip_bitmap);
156 color_strip_canvas.clear(SK_ColorTRANSPARENT);
158 // Draw a rounded rect of the |base_icon|'s dominant color.
159 SkPaint color_strip_paint;
160 color_strip_paint.setFlags(SkPaint::kAntiAlias_Flag);
161 color_strip_paint.setColor(
162 color_utils::CalculateKMeanColorOfBitmap(base_icon));
163 color_strip_canvas.drawRoundRect(SkRect::MakeWH(output_size, output_size),
164 kBorderRadius,
165 kBorderRadius,
166 color_strip_paint);
168 // Erase the top of the rounded rect to leave a color strip.
169 SkPaint clear_paint;
170 clear_paint.setColor(SK_ColorTRANSPARENT);
171 clear_paint.setXfermodeMode(SkXfermode::kSrc_Mode);
172 color_strip_canvas.drawRect(
173 SkRect::MakeWH(output_size, output_size - kColorStripHeight),
174 clear_paint);
176 // Draw each element to an output canvas.
177 SkBitmap generated_icon;
178 generated_icon.allocN32Pixels(output_size, output_size);
179 SkCanvas generated_icon_canvas(generated_icon);
180 generated_icon_canvas.clear(SK_ColorTRANSPARENT);
182 // Draw the background.
183 SkPaint background_paint;
184 background_paint.setColor(kBackgroundColor);
185 background_paint.setFlags(SkPaint::kAntiAlias_Flag);
186 generated_icon_canvas.drawRoundRect(SkRect::MakeWH(output_size, output_size),
187 kBorderRadius,
188 kBorderRadius,
189 background_paint);
191 // Draw the color strip.
192 generated_icon_canvas.drawBitmap(color_strip_bitmap, 0, 0);
194 // Draw the border.
195 SkPaint border_paint;
196 border_paint.setColor(kBorderColor);
197 border_paint.setStyle(SkPaint::kStroke_Style);
198 border_paint.setFlags(SkPaint::kAntiAlias_Flag);
199 generated_icon_canvas.drawRoundRect(SkRect::MakeWH(output_size, output_size),
200 kBorderRadius,
201 kBorderRadius,
202 border_paint);
204 // Draw the centered base icon to the output canvas.
205 generated_icon_canvas.drawBitmap(base_icon,
206 (output_size - base_icon.width()) / 2,
207 (output_size - base_icon.height()) / 2);
209 generated_icon.deepCopyTo(&(*bitmaps)[output_size]);
212 TabHelper::TabHelper(content::WebContents* web_contents)
213 : content::WebContentsObserver(web_contents),
214 extension_app_(NULL),
215 extension_function_dispatcher_(
216 Profile::FromBrowserContext(web_contents->GetBrowserContext()), this),
217 pending_web_app_action_(NONE),
218 script_executor_(new ScriptExecutor(web_contents,
219 &script_execution_observers_)),
220 location_bar_controller_(new PageActionController(web_contents)),
221 image_loader_ptr_factory_(this),
222 webstore_inline_installer_factory_(new WebstoreInlineInstallerFactory()) {
223 // The ActiveTabPermissionManager requires a session ID; ensure this
224 // WebContents has one.
225 SessionTabHelper::CreateForWebContents(web_contents);
226 if (web_contents->GetRenderViewHost())
227 SetTabId(web_contents->GetRenderViewHost());
228 active_tab_permission_granter_.reset(new ActiveTabPermissionGranter(
229 web_contents,
230 SessionID::IdForTab(web_contents),
231 Profile::FromBrowserContext(web_contents->GetBrowserContext())));
233 // If more classes need to listen to global content script activity, then
234 // a separate routing class with an observer interface should be written.
235 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
237 #if defined(ENABLE_EXTENSIONS)
238 AddScriptExecutionObserver(ActivityLog::GetInstance(profile_));
239 #endif
241 registrar_.Add(this,
242 content::NOTIFICATION_LOAD_STOP,
243 content::Source<NavigationController>(
244 &web_contents->GetController()));
246 registrar_.Add(this,
247 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
248 content::Source<CrxInstaller>(NULL));
250 registrar_.Add(this,
251 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
252 content::NotificationService::AllSources());
255 TabHelper::~TabHelper() {
256 #if defined(ENABLE_EXTENSIONS)
257 RemoveScriptExecutionObserver(ActivityLog::GetInstance(profile_));
258 #endif
261 void TabHelper::CreateApplicationShortcuts() {
262 DCHECK(CanCreateApplicationShortcuts());
263 NavigationEntry* entry =
264 web_contents()->GetController().GetLastCommittedEntry();
265 if (!entry)
266 return;
268 pending_web_app_action_ = CREATE_SHORTCUT;
270 // Start fetching web app info for CreateApplicationShortcut dialog and show
271 // the dialog when the data is available in OnDidGetApplicationInfo.
272 GetApplicationInfo(entry->GetPageID());
275 void TabHelper::CreateHostedAppFromWebContents() {
276 DCHECK(CanCreateApplicationShortcuts());
277 NavigationEntry* entry =
278 web_contents()->GetController().GetLastCommittedEntry();
279 if (!entry)
280 return;
282 pending_web_app_action_ = CREATE_HOSTED_APP;
284 // Start fetching web app info for CreateApplicationShortcut dialog and show
285 // the dialog when the data is available in OnDidGetApplicationInfo.
286 GetApplicationInfo(entry->GetPageID());
289 bool TabHelper::CanCreateApplicationShortcuts() const {
290 #if defined(OS_MACOSX)
291 return false;
292 #else
293 return web_app::IsValidUrl(web_contents()->GetURL()) &&
294 pending_web_app_action_ == NONE;
295 #endif
298 void TabHelper::SetExtensionApp(const Extension* extension) {
299 DCHECK(!extension || AppLaunchInfo::GetFullLaunchURL(extension).is_valid());
300 if (extension_app_ == extension)
301 return;
303 extension_app_ = extension;
305 UpdateExtensionAppIcon(extension_app_);
307 content::NotificationService::current()->Notify(
308 chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
309 content::Source<TabHelper>(this),
310 content::NotificationService::NoDetails());
313 void TabHelper::SetExtensionAppById(const std::string& extension_app_id) {
314 const Extension* extension = GetExtension(extension_app_id);
315 if (extension)
316 SetExtensionApp(extension);
319 void TabHelper::SetExtensionAppIconById(const std::string& extension_app_id) {
320 const Extension* extension = GetExtension(extension_app_id);
321 if (extension)
322 UpdateExtensionAppIcon(extension);
325 SkBitmap* TabHelper::GetExtensionAppIcon() {
326 if (extension_app_icon_.empty())
327 return NULL;
329 return &extension_app_icon_;
332 void TabHelper::RenderViewCreated(RenderViewHost* render_view_host) {
333 SetTabId(render_view_host);
336 void TabHelper::DidNavigateMainFrame(
337 const content::LoadCommittedDetails& details,
338 const content::FrameNavigateParams& params) {
339 #if defined(ENABLE_EXTENSIONS)
340 if (ExtensionSystem::Get(profile_)->extension_service() &&
341 RulesRegistryService::Get(profile_)) {
342 RulesRegistryService::Get(profile_)->content_rules_registry()->
343 DidNavigateMainFrame(web_contents(), details, params);
345 #endif // defined(ENABLE_EXTENSIONS)
347 Profile* profile =
348 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
349 ExtensionService* service = profile->GetExtensionService();
350 if (!service)
351 return;
353 if (CommandLine::ForCurrentProcess()->HasSwitch(
354 switches::kEnableStreamlinedHostedApps)) {
355 #if !defined(OS_ANDROID)
356 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
357 if (browser && browser->is_app()) {
358 SetExtensionApp(service->GetInstalledExtension(
359 web_app::GetExtensionIdFromApplicationName(browser->app_name())));
360 } else {
361 UpdateExtensionAppIcon(service->GetInstalledExtensionByUrl(params.url));
363 #endif
364 } else {
365 UpdateExtensionAppIcon(service->GetInstalledExtensionByUrl(params.url));
368 if (details.is_in_page)
369 return;
371 ExtensionActionManager* extension_action_manager =
372 ExtensionActionManager::Get(profile);
373 for (ExtensionSet::const_iterator it = service->extensions()->begin();
374 it != service->extensions()->end(); ++it) {
375 ExtensionAction* browser_action =
376 extension_action_manager->GetBrowserAction(*it->get());
377 if (browser_action) {
378 browser_action->ClearAllValuesForTab(SessionID::IdForTab(web_contents()));
379 content::NotificationService::current()->Notify(
380 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
381 content::Source<ExtensionAction>(browser_action),
382 content::NotificationService::NoDetails());
387 bool TabHelper::OnMessageReceived(const IPC::Message& message) {
388 bool handled = true;
389 IPC_BEGIN_MESSAGE_MAP(TabHelper, message)
390 IPC_MESSAGE_HANDLER(ChromeExtensionHostMsg_DidGetApplicationInfo,
391 OnDidGetApplicationInfo)
392 IPC_MESSAGE_HANDLER(ExtensionHostMsg_InlineWebstoreInstall,
393 OnInlineWebstoreInstall)
394 IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppInstallState,
395 OnGetAppInstallState);
396 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
397 IPC_MESSAGE_HANDLER(ExtensionHostMsg_ContentScriptsExecuting,
398 OnContentScriptsExecuting)
399 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
400 OnWatchedPageChange)
401 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DetailedConsoleMessageAdded,
402 OnDetailedConsoleMessageAdded)
403 IPC_MESSAGE_UNHANDLED(handled = false)
404 IPC_END_MESSAGE_MAP()
405 return handled;
408 void TabHelper::CreateHostedApp() {
409 // Add urls from the WebApplicationInfo.
410 std::vector<GURL> web_app_info_icon_urls;
411 for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it =
412 web_app_info_.icons.begin();
413 it != web_app_info_.icons.end(); ++it) {
414 if (it->url.is_valid())
415 web_app_info_icon_urls.push_back(it->url);
418 favicon_downloader_.reset(
419 new FaviconDownloader(web_contents(),
420 web_app_info_icon_urls,
421 base::Bind(&TabHelper::FinishCreateHostedApp,
422 base::Unretained(this))));
423 favicon_downloader_->Start();
426 // TODO(calamity): Move hosted app generation into its own file.
427 void TabHelper::FinishCreateHostedApp(
428 bool success,
429 const std::map<GURL, std::vector<SkBitmap> >& bitmaps) {
430 // The tab has navigated away during the icon download. Cancel the hosted app
431 // creation.
432 if (!success) {
433 favicon_downloader_.reset();
434 return;
437 if (web_app_info_.app_url.is_empty())
438 web_app_info_.app_url = web_contents()->GetURL();
440 if (web_app_info_.title.empty())
441 web_app_info_.title = web_contents()->GetTitle();
442 if (web_app_info_.title.empty())
443 web_app_info_.title = base::UTF8ToUTF16(web_app_info_.app_url.spec());
445 // Add the downloaded icons. Extensions only allow certain icon sizes. First
446 // populate icons that match the allowed sizes exactly and then downscale
447 // remaining icons to the closest allowed size that doesn't yet have an icon.
448 std::set<int> allowed_sizes(
449 extension_misc::kExtensionIconSizes,
450 extension_misc::kExtensionIconSizes +
451 extension_misc::kNumExtensionIconSizes);
452 std::vector<SkBitmap> downloaded_icons;
453 for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin();
454 map_it != bitmaps.end(); ++map_it) {
455 for (std::vector<SkBitmap>::const_iterator bitmap_it =
456 map_it->second.begin();
457 bitmap_it != map_it->second.end(); ++bitmap_it) {
458 if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height())
459 continue;
461 downloaded_icons.push_back(*bitmap_it);
465 // If there are icons that don't match the accepted icon sizes, find the
466 // closest bigger icon to the accepted sizes and resize the icon to it. An
467 // icon will be resized and used for at most one size.
468 std::map<int, SkBitmap> resized_bitmaps(
469 TabHelper::ConstrainBitmapsToSizes(downloaded_icons,
470 allowed_sizes));
472 // Generate container icons from smaller icons.
473 const int kIconSizesToGenerate[] = {
474 extension_misc::EXTENSION_ICON_SMALL,
475 extension_misc::EXTENSION_ICON_MEDIUM,
477 const std::set<int> generate_sizes(
478 kIconSizesToGenerate,
479 kIconSizesToGenerate + arraysize(kIconSizesToGenerate));
481 // Only generate icons if larger icons don't exist. This means the app
482 // launcher and the taskbar will do their best downsizing large icons and
483 // these container icons are only generated as a last resort against upscaling
484 // a smaller icon.
485 if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) ==
486 resized_bitmaps.end()) {
487 // Generate these from biggest to smallest so we don't end up with
488 // concentric container icons.
489 for (std::set<int>::const_reverse_iterator it = generate_sizes.rbegin();
490 it != generate_sizes.rend(); ++it) {
491 TabHelper::GenerateContainerIcon(&resized_bitmaps, *it);
495 // Populate a the icon data into the WebApplicationInfo we are using to
496 // install the bookmark app.
497 for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it =
498 resized_bitmaps.begin();
499 resized_bitmaps_it != resized_bitmaps.end(); ++resized_bitmaps_it) {
500 WebApplicationInfo::IconInfo icon_info;
501 icon_info.data = resized_bitmaps_it->second;
502 icon_info.width = icon_info.data.width();
503 icon_info.height = icon_info.data.height();
504 web_app_info_.icons.push_back(icon_info);
507 // Install the app.
508 Profile* profile =
509 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
510 scoped_refptr<extensions::CrxInstaller> installer(
511 extensions::CrxInstaller::CreateSilent(profile->GetExtensionService()));
512 installer->set_error_on_unsupported_requirements(true);
513 installer->InstallWebApp(web_app_info_);
514 favicon_downloader_.reset();
517 void TabHelper::DidCloneToNewWebContents(WebContents* old_web_contents,
518 WebContents* new_web_contents) {
519 // When the WebContents that this is attached to is cloned, give the new clone
520 // a TabHelper and copy state over.
521 CreateForWebContents(new_web_contents);
522 TabHelper* new_helper = FromWebContents(new_web_contents);
524 new_helper->SetExtensionApp(extension_app());
525 new_helper->extension_app_icon_ = extension_app_icon_;
528 void TabHelper::OnDidGetApplicationInfo(int32 page_id,
529 const WebApplicationInfo& info) {
530 // Android does not implement BrowserWindow.
531 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
532 web_app_info_ = info;
534 NavigationEntry* entry =
535 web_contents()->GetController().GetLastCommittedEntry();
536 if (!entry || (entry->GetPageID() != page_id))
537 return;
539 switch (pending_web_app_action_) {
540 case CREATE_SHORTCUT: {
541 chrome::ShowCreateWebAppShortcutsDialog(
542 web_contents()->GetView()->GetTopLevelNativeWindow(),
543 web_contents());
544 break;
546 case CREATE_HOSTED_APP: {
547 CreateHostedApp();
548 break;
550 case UPDATE_SHORTCUT: {
551 web_app::UpdateShortcutForTabContents(web_contents());
552 break;
554 default:
555 NOTREACHED();
556 break;
559 // The hosted app action will be cleared once the installation completes or
560 // fails.
561 if (pending_web_app_action_ != CREATE_HOSTED_APP)
562 pending_web_app_action_ = NONE;
563 #endif
566 void TabHelper::OnInlineWebstoreInstall(
567 int install_id,
568 int return_route_id,
569 const std::string& webstore_item_id,
570 const GURL& requestor_url) {
571 WebstoreStandaloneInstaller::Callback callback =
572 base::Bind(&TabHelper::OnInlineInstallComplete, base::Unretained(this),
573 install_id, return_route_id);
574 scoped_refptr<WebstoreInlineInstaller> installer(
575 webstore_inline_installer_factory_->CreateInstaller(
576 web_contents(),
577 webstore_item_id,
578 requestor_url,
579 callback));
580 installer->BeginInstall();
583 void TabHelper::OnGetAppInstallState(const GURL& requestor_url,
584 int return_route_id,
585 int callback_id) {
586 ExtensionRegistry* registry =
587 ExtensionRegistry::Get(web_contents()->GetBrowserContext());
588 const ExtensionSet& extensions = registry->enabled_extensions();
589 const ExtensionSet& disabled_extensions = registry->disabled_extensions();
591 std::string state;
592 if (extensions.GetHostedAppByURL(requestor_url))
593 state = extension_misc::kAppStateInstalled;
594 else if (disabled_extensions.GetHostedAppByURL(requestor_url))
595 state = extension_misc::kAppStateDisabled;
596 else
597 state = extension_misc::kAppStateNotInstalled;
599 Send(new ExtensionMsg_GetAppInstallStateResponse(
600 return_route_id, state, callback_id));
603 void TabHelper::OnRequest(const ExtensionHostMsg_Request_Params& request) {
604 extension_function_dispatcher_.Dispatch(request,
605 web_contents()->GetRenderViewHost());
608 void TabHelper::OnContentScriptsExecuting(
609 const ScriptExecutionObserver::ExecutingScriptsMap& executing_scripts_map,
610 int32 on_page_id,
611 const GURL& on_url) {
612 FOR_EACH_OBSERVER(ScriptExecutionObserver, script_execution_observers_,
613 OnScriptsExecuted(web_contents(),
614 executing_scripts_map,
615 on_page_id,
616 on_url));
619 void TabHelper::OnWatchedPageChange(
620 const std::vector<std::string>& css_selectors) {
621 #if defined(ENABLE_EXTENSIONS)
622 if (ExtensionSystem::Get(profile_)->extension_service() &&
623 RulesRegistryService::Get(profile_)) {
624 RulesRegistryService::Get(profile_)->content_rules_registry()->Apply(
625 web_contents(), css_selectors);
627 #endif // defined(ENABLE_EXTENSIONS)
630 void TabHelper::OnDetailedConsoleMessageAdded(
631 const base::string16& message,
632 const base::string16& source,
633 const StackTrace& stack_trace,
634 int32 severity_level) {
635 if (IsSourceFromAnExtension(source)) {
636 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
637 ErrorConsole::Get(profile_)->ReportError(
638 scoped_ptr<ExtensionError>(new RuntimeError(
639 extension_app_ ? extension_app_->id() : std::string(),
640 profile_->IsOffTheRecord(),
641 source,
642 message,
643 stack_trace,
644 web_contents() ?
645 web_contents()->GetLastCommittedURL() : GURL::EmptyGURL(),
646 static_cast<logging::LogSeverity>(severity_level),
647 rvh->GetRoutingID(),
648 rvh->GetProcess()->GetID())));
652 const Extension* TabHelper::GetExtension(const std::string& extension_app_id) {
653 if (extension_app_id.empty())
654 return NULL;
656 Profile* profile =
657 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
658 ExtensionService* extension_service = profile->GetExtensionService();
659 if (!extension_service || !extension_service->is_ready())
660 return NULL;
662 const Extension* extension =
663 extension_service->GetExtensionById(extension_app_id, false);
664 return extension;
667 void TabHelper::UpdateExtensionAppIcon(const Extension* extension) {
668 extension_app_icon_.reset();
669 // Ensure previously enqueued callbacks are ignored.
670 image_loader_ptr_factory_.InvalidateWeakPtrs();
672 // Enqueue OnImageLoaded callback.
673 if (extension) {
674 Profile* profile =
675 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
676 extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile);
677 loader->LoadImageAsync(
678 extension,
679 IconsInfo::GetIconResource(extension,
680 extension_misc::EXTENSION_ICON_SMALL,
681 ExtensionIconSet::MATCH_BIGGER),
682 gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
683 extension_misc::EXTENSION_ICON_SMALL),
684 base::Bind(&TabHelper::OnImageLoaded,
685 image_loader_ptr_factory_.GetWeakPtr()));
689 void TabHelper::SetAppIcon(const SkBitmap& app_icon) {
690 extension_app_icon_ = app_icon;
691 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
694 void TabHelper::SetWebstoreInlineInstallerFactoryForTests(
695 WebstoreInlineInstallerFactory* factory) {
696 webstore_inline_installer_factory_.reset(factory);
699 void TabHelper::OnImageLoaded(const gfx::Image& image) {
700 if (!image.IsEmpty()) {
701 extension_app_icon_ = *image.ToSkBitmap();
702 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
706 WindowController* TabHelper::GetExtensionWindowController() const {
707 return ExtensionTabUtil::GetWindowControllerOfTab(web_contents());
710 void TabHelper::OnInlineInstallComplete(int install_id,
711 int return_route_id,
712 bool success,
713 const std::string& error) {
714 Send(new ExtensionMsg_InlineWebstoreInstallResponse(
715 return_route_id, install_id, success, success ? std::string() : error));
718 WebContents* TabHelper::GetAssociatedWebContents() const {
719 return web_contents();
722 void TabHelper::GetApplicationInfo(int32 page_id) {
723 Send(new ChromeExtensionMsg_GetApplicationInfo(routing_id(), page_id));
726 void TabHelper::Observe(int type,
727 const content::NotificationSource& source,
728 const content::NotificationDetails& details) {
729 switch (type) {
730 case content::NOTIFICATION_LOAD_STOP: {
731 const NavigationController& controller =
732 *content::Source<NavigationController>(source).ptr();
733 DCHECK_EQ(controller.GetWebContents(), web_contents());
735 if (pending_web_app_action_ == UPDATE_SHORTCUT) {
736 // Schedule a shortcut update when web application info is available if
737 // last committed entry is not NULL. Last committed entry could be NULL
738 // when an interstitial page is injected (e.g. bad https certificate,
739 // malware site etc). When this happens, we abort the shortcut update.
740 NavigationEntry* entry = controller.GetLastCommittedEntry();
741 if (entry)
742 GetApplicationInfo(entry->GetPageID());
743 else
744 pending_web_app_action_ = NONE;
746 break;
748 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
749 if (pending_web_app_action_ != CREATE_HOSTED_APP)
750 return;
752 pending_web_app_action_ = NONE;
754 const Extension* extension =
755 content::Details<const Extension>(details).ptr();
756 if (!extension ||
757 AppLaunchInfo::GetLaunchWebURL(extension) != web_app_info_.app_url)
758 return;
760 #if defined(OS_CHROMEOS)
761 ChromeLauncherController::instance()->PinAppWithID(extension->id());
762 #endif
764 // Android does not implement browser_finder.cc.
765 #if !defined(OS_ANDROID)
766 Browser* browser =
767 chrome::FindBrowserWithWebContents(web_contents());
768 if (browser) {
769 browser->window()->ShowBookmarkAppBubble(web_app_info_,
770 extension->id());
772 #endif
774 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
775 if (pending_web_app_action_ == CREATE_HOSTED_APP)
776 pending_web_app_action_ = NONE;
777 break;
782 void TabHelper::SetTabId(RenderViewHost* render_view_host) {
783 render_view_host->Send(
784 new ExtensionMsg_SetTabId(render_view_host->GetRoutingID(),
785 SessionID::IdForTab(web_contents())));
788 } // namespace extensions