tab_helper.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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. 4 5#include "chrome/browser/extensions/tab_helper.h" 6 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" 71 72#if defined(OS_CHROMEOS) 73#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" 74#endif 75 76using content::NavigationController; 77using content::NavigationEntry; 78using content::RenderViewHost; 79using content::WebContents; 80 81DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::TabHelper); 82 83namespace extensions { 84 85TabHelper::ScriptExecutionObserver::ScriptExecutionObserver( 86 TabHelper* tab_helper) 87 : tab_helper_(tab_helper) { 88 tab_helper_->AddScriptExecutionObserver(this); 89} 90 91TabHelper::ScriptExecutionObserver::ScriptExecutionObserver() 92 : tab_helper_(NULL) { 93} 94 95TabHelper::ScriptExecutionObserver::~ScriptExecutionObserver() { 96 if (tab_helper_) 97 tab_helper_->RemoveScriptExecutionObserver(this); 98} 99 100// static 101std::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; 110 } 111 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); 128 } 129 } 130 return output_bitmaps; 131} 132 133// static 134void 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; 142 143 --it; 144 // This is the biggest icon smaller than |output_size|. 145 const SkBitmap& base_icon = it->second; 146 147 const size_t kBorderRadius = 5; 148 const size_t kColorStripHeight = 3; 149 const SkColor kBorderColor = 0xFFD5D5D5; 150 const SkColor kBackgroundColor = 0xFFFFFFFF; 151 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); 157 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); 167 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); 175 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); 181 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); 190 191 // Draw the color strip. 192 generated_icon_canvas.drawBitmap(color_strip_bitmap, 0, 0); 193 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); 203 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); 208 209 generated_icon.deepCopyTo(&(*bitmaps)[output_size]); 210} 211 212TabHelper::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()))); 232 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()); 236 237#if defined(ENABLE_EXTENSIONS) 238 AddScriptExecutionObserver(ActivityLog::GetInstance(profile_)); 239#endif 240 241 registrar_.Add(this, 242 content::NOTIFICATION_LOAD_STOP, 243 content::Source<NavigationController>( 244 &web_contents->GetController())); 245 246 registrar_.Add(this, 247 chrome::NOTIFICATION_CRX_INSTALLER_DONE, 248 content::Source<CrxInstaller>(NULL)); 249 250 registrar_.Add(this, 251 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, 252 content::NotificationService::AllSources()); 253} 254 255TabHelper::~TabHelper() { 256#if defined(ENABLE_EXTENSIONS) 257 RemoveScriptExecutionObserver(ActivityLog::GetInstance(profile_)); 258#endif 259} 260 261void TabHelper::CreateApplicationShortcuts() { 262 DCHECK(CanCreateApplicationShortcuts()); 263 NavigationEntry* entry = 264 web_contents()->GetController().GetLastCommittedEntry(); 265 if (!entry) 266 return; 267 268 pending_web_app_action_ = CREATE_SHORTCUT; 269 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()); 273} 274 275void TabHelper::CreateHostedAppFromWebContents() { 276 DCHECK(CanCreateApplicationShortcuts()); 277 NavigationEntry* entry = 278 web_contents()->GetController().GetLastCommittedEntry(); 279 if (!entry) 280 return; 281 282 pending_web_app_action_ = CREATE_HOSTED_APP; 283 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()); 287} 288 289bool 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 296} 297 298void TabHelper::SetExtensionApp(const Extension* extension) { 299 DCHECK(!extension || AppLaunchInfo::GetFullLaunchURL(extension).is_valid()); 300 if (extension_app_ == extension) 301 return; 302 303 extension_app_ = extension; 304 305 UpdateExtensionAppIcon(extension_app_); 306 307 content::NotificationService::current()->Notify( 308 chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, 309 content::Source<TabHelper>(this), 310 content::NotificationService::NoDetails()); 311} 312 313void TabHelper::SetExtensionAppById(const std::string& extension_app_id) { 314 const Extension* extension = GetExtension(extension_app_id); 315 if (extension) 316 SetExtensionApp(extension); 317} 318 319void TabHelper::SetExtensionAppIconById(const std::string& extension_app_id) { 320 const Extension* extension = GetExtension(extension_app_id); 321 if (extension) 322 UpdateExtensionAppIcon(extension); 323} 324 325SkBitmap* TabHelper::GetExtensionAppIcon() { 326 if (extension_app_icon_.empty()) 327 return NULL; 328 329 return &extension_app_icon_; 330} 331 332void TabHelper::RenderViewCreated(RenderViewHost* render_view_host) { 333 SetTabId(render_view_host); 334} 335 336void 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); 344 } 345#endif // defined(ENABLE_EXTENSIONS) 346 347 Profile* profile = 348 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 349 ExtensionService* service = profile->GetExtensionService(); 350 if (!service) 351 return; 352 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)); 362 } 363#endif 364 } else { 365 UpdateExtensionAppIcon(service->GetInstalledExtensionByUrl(params.url)); 366 } 367 368 if (details.is_in_page) 369 return; 370 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()); 383 } 384 } 385} 386 387bool 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; 406} 407 408void 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); 416 } 417 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(); 424} 425 426// TODO(calamity): Move hosted app generation into its own file. 427void 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; 435 } 436 437 if (web_app_info_.app_url.is_empty()) 438 web_app_info_.app_url = web_contents()->GetURL(); 439 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()); 444 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; 460 461 downloaded_icons.push_back(*bitmap_it); 462 } 463 } 464 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)); 471 472 // Generate container icons from smaller icons. 473 const int kIconSizesToGenerate[] = { 474 extension_misc::EXTENSION_ICON_SMALL, 475 extension_misc::EXTENSION_ICON_MEDIUM, 476 }; 477 const std::set<int> generate_sizes( 478 kIconSizesToGenerate, 479 kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); 480 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); 492 } 493 } 494 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); 505 } 506 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(); 515} 516 517void 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); 523 524 new_helper->SetExtensionApp(extension_app()); 525 new_helper->extension_app_icon_ = extension_app_icon_; 526} 527 528void 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; 533 534 NavigationEntry* entry = 535 web_contents()->GetController().GetLastCommittedEntry(); 536 if (!entry || (entry->GetPageID() != page_id)) 537 return; 538 539 switch (pending_web_app_action_) { 540 case CREATE_SHORTCUT: { 541 chrome::ShowCreateWebAppShortcutsDialog( 542 web_contents()->GetView()->GetTopLevelNativeWindow(), 543 web_contents()); 544 break; 545 } 546 case CREATE_HOSTED_APP: { 547 CreateHostedApp(); 548 break; 549 } 550 case UPDATE_SHORTCUT: { 551 web_app::UpdateShortcutForTabContents(web_contents()); 552 break; 553 } 554 default: 555 NOTREACHED(); 556 break; 557 } 558 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 564} 565 566void 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(); 581} 582 583void 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(); 590 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; 598 599 Send(new ExtensionMsg_GetAppInstallStateResponse( 600 return_route_id, state, callback_id)); 601} 602 603void TabHelper::OnRequest(const ExtensionHostMsg_Request_Params& request) { 604 extension_function_dispatcher_.Dispatch(request, 605 web_contents()->GetRenderViewHost()); 606} 607 608void 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)); 617} 618 619void 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); 626 } 627#endif // defined(ENABLE_EXTENSIONS) 628} 629 630void 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()))); 649 } 650} 651 652const Extension* TabHelper::GetExtension(const std::string& extension_app_id) { 653 if (extension_app_id.empty()) 654 return NULL; 655 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; 661 662 const Extension* extension = 663 extension_service->GetExtensionById(extension_app_id, false); 664 return extension; 665} 666 667void TabHelper::UpdateExtensionAppIcon(const Extension* extension) { 668 extension_app_icon_.reset(); 669 // Ensure previously enqueued callbacks are ignored. 670 image_loader_ptr_factory_.InvalidateWeakPtrs(); 671 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())); 686 } 687} 688 689void TabHelper::SetAppIcon(const SkBitmap& app_icon) { 690 extension_app_icon_ = app_icon; 691 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE); 692} 693 694void TabHelper::SetWebstoreInlineInstallerFactoryForTests( 695 WebstoreInlineInstallerFactory* factory) { 696 webstore_inline_installer_factory_.reset(factory); 697} 698 699void TabHelper::OnImageLoaded(const gfx::Image& image) { 700 if (!image.IsEmpty()) { 701 extension_app_icon_ = *image.ToSkBitmap(); 702 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); 703 } 704} 705 706WindowController* TabHelper::GetExtensionWindowController() const { 707 return ExtensionTabUtil::GetWindowControllerOfTab(web_contents()); 708} 709 710void 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)); 716} 717 718WebContents* TabHelper::GetAssociatedWebContents() const { 719 return web_contents(); 720} 721 722void TabHelper::GetApplicationInfo(int32 page_id) { 723 Send(new ChromeExtensionMsg_GetApplicationInfo(routing_id(), page_id)); 724} 725 726void 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()); 734 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; 745 } 746 break; 747 } 748 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: { 749 if (pending_web_app_action_ != CREATE_HOSTED_APP) 750 return; 751 752 pending_web_app_action_ = NONE; 753 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; 759 760#if defined(OS_CHROMEOS) 761 ChromeLauncherController::instance()->PinAppWithID(extension->id()); 762#endif 763 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()); 771 } 772#endif 773 } 774 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: { 775 if (pending_web_app_action_ == CREATE_HOSTED_APP) 776 pending_web_app_action_ = NONE; 777 break; 778 } 779 } 780} 781 782void TabHelper::SetTabId(RenderViewHost* render_view_host) { 783 render_view_host->Send( 784 new ExtensionMsg_SetTabId(render_view_host->GetRoutingID(), 785 SessionID::IdForTab(web_contents()))); 786} 787 788} // namespace extensions 789