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"
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()
95 TabHelper::ScriptExecutionObserver::~ScriptExecutionObserver() {
97 tab_helper_
->RemoveScriptExecutionObserver(this);
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
);
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
125 : skia::ImageOperations::Resize(
126 bitmaps_it
->second
, skia::ImageOperations::RESIZE_LANCZOS3
,
130 return output_bitmaps
;
134 void TabHelper::GenerateContainerIcon(std::map
<int, SkBitmap
>* bitmaps
,
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
))
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
),
168 // Erase the top of the rounded rect to leave a color strip.
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
),
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
),
191 // Draw the color strip.
192 generated_icon_canvas
.drawBitmap(color_strip_bitmap
, 0, 0);
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
),
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(
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_
));
242 content::NOTIFICATION_LOAD_STOP
,
243 content::Source
<NavigationController
>(
244 &web_contents
->GetController()));
247 chrome::NOTIFICATION_CRX_INSTALLER_DONE
,
248 content::Source
<CrxInstaller
>(NULL
));
251 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR
,
252 content::NotificationService::AllSources());
255 TabHelper::~TabHelper() {
256 #if defined(ENABLE_EXTENSIONS)
257 RemoveScriptExecutionObserver(ActivityLog::GetInstance(profile_
));
261 void TabHelper::CreateApplicationShortcuts() {
262 DCHECK(CanCreateApplicationShortcuts());
263 NavigationEntry
* entry
=
264 web_contents()->GetController().GetLastCommittedEntry();
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();
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)
293 return web_app::IsValidUrl(web_contents()->GetURL()) &&
294 pending_web_app_action_
== NONE
;
298 void TabHelper::SetExtensionApp(const Extension
* extension
) {
299 DCHECK(!extension
|| AppLaunchInfo::GetFullLaunchURL(extension
).is_valid());
300 if (extension_app_
== extension
)
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
);
316 SetExtensionApp(extension
);
319 void TabHelper::SetExtensionAppIconById(const std::string
& extension_app_id
) {
320 const Extension
* extension
= GetExtension(extension_app_id
);
322 UpdateExtensionAppIcon(extension
);
325 SkBitmap
* TabHelper::GetExtensionAppIcon() {
326 if (extension_app_icon_
.empty())
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)
348 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
349 ExtensionService
* service
= profile
->GetExtensionService();
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())));
361 UpdateExtensionAppIcon(service
->GetInstalledExtensionByUrl(params
.url
));
365 UpdateExtensionAppIcon(service
->GetInstalledExtensionByUrl(params
.url
));
368 if (details
.is_in_page
)
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
) {
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
,
401 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DetailedConsoleMessageAdded
,
402 OnDetailedConsoleMessageAdded
)
403 IPC_MESSAGE_UNHANDLED(handled
= false)
404 IPC_END_MESSAGE_MAP()
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(
429 const std::map
<GURL
, std::vector
<SkBitmap
> >& bitmaps
) {
430 // The tab has navigated away during the icon download. Cancel the hosted app
433 favicon_downloader_
.reset();
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())
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
,
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
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
);
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
))
539 switch (pending_web_app_action_
) {
540 case CREATE_SHORTCUT
: {
541 chrome::ShowCreateWebAppShortcutsDialog(
542 web_contents()->GetView()->GetTopLevelNativeWindow(),
546 case CREATE_HOSTED_APP
: {
550 case UPDATE_SHORTCUT
: {
551 web_app::UpdateShortcutForTabContents(web_contents());
559 // The hosted app action will be cleared once the installation completes or
561 if (pending_web_app_action_
!= CREATE_HOSTED_APP
)
562 pending_web_app_action_
= NONE
;
566 void TabHelper::OnInlineWebstoreInstall(
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(
580 installer
->BeginInstall();
583 void TabHelper::OnGetAppInstallState(const GURL
& requestor_url
,
586 ExtensionRegistry
* registry
=
587 ExtensionRegistry::Get(web_contents()->GetBrowserContext());
588 const ExtensionSet
& extensions
= registry
->enabled_extensions();
589 const ExtensionSet
& disabled_extensions
= registry
->disabled_extensions();
592 if (extensions
.GetHostedAppByURL(requestor_url
))
593 state
= extension_misc::kAppStateInstalled
;
594 else if (disabled_extensions
.GetHostedAppByURL(requestor_url
))
595 state
= extension_misc::kAppStateDisabled
;
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
,
611 const GURL
& on_url
) {
612 FOR_EACH_OBSERVER(ScriptExecutionObserver
, script_execution_observers_
,
613 OnScriptsExecuted(web_contents(),
614 executing_scripts_map
,
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(),
645 web_contents()->GetLastCommittedURL() : GURL::EmptyGURL(),
646 static_cast<logging::LogSeverity
>(severity_level
),
648 rvh
->GetProcess()->GetID())));
652 const Extension
* TabHelper::GetExtension(const std::string
& extension_app_id
) {
653 if (extension_app_id
.empty())
657 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
658 ExtensionService
* extension_service
= profile
->GetExtensionService();
659 if (!extension_service
|| !extension_service
->is_ready())
662 const Extension
* extension
=
663 extension_service
->GetExtensionById(extension_app_id
, false);
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.
675 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
676 extensions::ImageLoader
* loader
= extensions::ImageLoader::Get(profile
);
677 loader
->LoadImageAsync(
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
,
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
) {
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();
742 GetApplicationInfo(entry
->GetPageID());
744 pending_web_app_action_
= NONE
;
748 case chrome::NOTIFICATION_CRX_INSTALLER_DONE
: {
749 if (pending_web_app_action_
!= CREATE_HOSTED_APP
)
752 pending_web_app_action_
= NONE
;
754 const Extension
* extension
=
755 content::Details
<const Extension
>(details
).ptr();
757 AppLaunchInfo::GetLaunchWebURL(extension
) != web_app_info_
.app_url
)
760 #if defined(OS_CHROMEOS)
761 ChromeLauncherController::instance()->PinAppWithID(extension
->id());
764 // Android does not implement browser_finder.cc.
765 #if !defined(OS_ANDROID)
767 chrome::FindBrowserWithWebContents(web_contents());
769 browser
->window()->ShowBookmarkAppBubble(web_app_info_
,
774 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR
: {
775 if (pending_web_app_action_
== CREATE_HOSTED_APP
)
776 pending_web_app_action_
= NONE
;
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