tab_helper.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/extension_constants.h" 40#include "chrome/common/extensions/extension_icon_set.h" 41#include "chrome/common/extensions/extension_messages.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_resource.h" 64#include "extensions/common/extension_urls.h" 65#include "extensions/common/feature_switch.h" 66#include "skia/ext/image_operations.h" 67#include "skia/ext/platform_canvas.h" 68#include "ui/gfx/color_analysis.h" 69#include "ui/gfx/image/image.h" 70 71#if defined(OS_CHROMEOS) 72#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" 73#endif 74 75using content::NavigationController; 76using content::NavigationEntry; 77using content::RenderViewHost; 78using content::WebContents; 79 80DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::TabHelper); 81 82namespace extensions { 83 84TabHelper::ScriptExecutionObserver::ScriptExecutionObserver( 85 TabHelper* tab_helper) 86 : tab_helper_(tab_helper) { 87 tab_helper_->AddScriptExecutionObserver(this); 88} 89 90TabHelper::ScriptExecutionObserver::ScriptExecutionObserver() 91 : tab_helper_(NULL) { 92} 93 94TabHelper::ScriptExecutionObserver::~ScriptExecutionObserver() { 95 if (tab_helper_) 96 tab_helper_->RemoveScriptExecutionObserver(this); 97} 98 99// static 100std::map<int, SkBitmap> TabHelper::ConstrainBitmapsToSizes( 101 const std::vector<SkBitmap>& bitmaps, 102 const std::set<int>& sizes) { 103 std::map<int, SkBitmap> output_bitmaps; 104 std::map<int, SkBitmap> ordered_bitmaps; 105 for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin(); 106 it != bitmaps.end(); ++it) { 107 DCHECK(it->width() == it->height()); 108 ordered_bitmaps[it->width()] = *it; 109 } 110 111 std::set<int>::const_iterator sizes_it = sizes.begin(); 112 std::map<int, SkBitmap>::const_iterator bitmaps_it = ordered_bitmaps.begin(); 113 while (sizes_it != sizes.end() && bitmaps_it != ordered_bitmaps.end()) { 114 int size = *sizes_it; 115 // Find the closest not-smaller bitmap. 116 bitmaps_it = ordered_bitmaps.lower_bound(size); 117 ++sizes_it; 118 // Ensure the bitmap is valid and smaller than the next allowed size. 119 if (bitmaps_it != ordered_bitmaps.end() && 120 (sizes_it == sizes.end() || bitmaps_it->second.width() < *sizes_it)) { 121 // Resize the bitmap if it does not exactly match the desired size. 122 output_bitmaps[size] = bitmaps_it->second.width() == size 123 ? bitmaps_it->second 124 : skia::ImageOperations::Resize( 125 bitmaps_it->second, skia::ImageOperations::RESIZE_LANCZOS3, 126 size, size); 127 } 128 } 129 return output_bitmaps; 130} 131 132// static 133void TabHelper::GenerateContainerIcon(std::map<int, SkBitmap>* bitmaps, 134 int output_size) { 135 std::map<int, SkBitmap>::const_iterator it = 136 bitmaps->lower_bound(output_size); 137 // Do nothing if there is no icon smaller than the desired size or there is 138 // already an icon of |output_size|. 139 if (it == bitmaps->begin() || bitmaps->count(output_size)) 140 return; 141 142 --it; 143 // This is the biggest icon smaller than |output_size|. 144 const SkBitmap& base_icon = it->second; 145 146 const size_t kBorderRadius = 5; 147 const size_t kColorStripHeight = 3; 148 const SkColor kBorderColor = 0xFFD5D5D5; 149 const SkColor kBackgroundColor = 0xFFFFFFFF; 150 151 // Create a separate canvas for the color strip. 152 scoped_ptr<SkCanvas> color_strip_canvas( 153 skia::CreateBitmapCanvas(output_size, output_size, false)); 154 DCHECK(color_strip_canvas); 155 156 // Draw a rounded rect of the |base_icon|'s dominant color. 157 SkPaint color_strip_paint; 158 color_utils::GridSampler sampler; 159 color_strip_paint.setFlags(SkPaint::kAntiAlias_Flag); 160 color_strip_paint.setColor( 161 color_utils::CalculateKMeanColorOfPNG( 162 gfx::Image::CreateFrom1xBitmap(base_icon).As1xPNGBytes(), 163 100, 665, &sampler)); 164 color_strip_canvas->drawRoundRect( 165 SkRect::MakeWH(output_size, output_size), 166 kBorderRadius, kBorderRadius, 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 scoped_ptr<SkCanvas> canvas( 178 skia::CreateBitmapCanvas(output_size, output_size, false)); 179 DCHECK(canvas); 180 181 // Draw the background. 182 SkPaint background_paint; 183 background_paint.setColor(kBackgroundColor); 184 background_paint.setFlags(SkPaint::kAntiAlias_Flag); 185 canvas->drawRoundRect( 186 SkRect::MakeWH(output_size, output_size), 187 kBorderRadius, kBorderRadius, background_paint); 188 189 // Draw the color strip. 190 canvas->drawBitmap(color_strip_canvas->getDevice()->accessBitmap(false), 191 0, 0); 192 193 // Draw the border. 194 SkPaint border_paint; 195 border_paint.setColor(kBorderColor); 196 border_paint.setStyle(SkPaint::kStroke_Style); 197 border_paint.setFlags(SkPaint::kAntiAlias_Flag); 198 canvas->drawRoundRect( 199 SkRect::MakeWH(output_size, output_size), 200 kBorderRadius, kBorderRadius, border_paint); 201 202 // Draw the centered base icon to the output canvas. 203 canvas->drawBitmap(base_icon, 204 (output_size - base_icon.width()) / 2, 205 (output_size - base_icon.height()) / 2); 206 207 const SkBitmap& generated_icon = 208 canvas->getDevice()->accessBitmap(false); 209 generated_icon.deepCopyTo(&(*bitmaps)[output_size], 210 generated_icon.getConfig()); 211} 212 213TabHelper::TabHelper(content::WebContents* web_contents) 214 : content::WebContentsObserver(web_contents), 215 extension_app_(NULL), 216 extension_function_dispatcher_( 217 Profile::FromBrowserContext(web_contents->GetBrowserContext()), this), 218 pending_web_app_action_(NONE), 219 script_executor_(new ScriptExecutor(web_contents, 220 &script_execution_observers_)), 221 location_bar_controller_(new PageActionController(web_contents)), 222 image_loader_ptr_factory_(this), 223 webstore_inline_installer_factory_(new WebstoreInlineInstallerFactory()) { 224 // The ActiveTabPermissionManager requires a session ID; ensure this 225 // WebContents has one. 226 SessionTabHelper::CreateForWebContents(web_contents); 227 if (web_contents->GetRenderViewHost()) 228 SetTabId(web_contents->GetRenderViewHost()); 229 active_tab_permission_granter_.reset(new ActiveTabPermissionGranter( 230 web_contents, 231 SessionID::IdForTab(web_contents), 232 Profile::FromBrowserContext(web_contents->GetBrowserContext()))); 233 234 // If more classes need to listen to global content script activity, then 235 // a separate routing class with an observer interface should be written. 236 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext()); 237 238#if defined(ENABLE_EXTENSIONS) 239 AddScriptExecutionObserver(ActivityLog::GetInstance(profile_)); 240#endif 241 242 registrar_.Add(this, 243 content::NOTIFICATION_LOAD_STOP, 244 content::Source<NavigationController>( 245 &web_contents->GetController())); 246 247 registrar_.Add(this, 248 chrome::NOTIFICATION_CRX_INSTALLER_DONE, 249 content::Source<CrxInstaller>(NULL)); 250 251 registrar_.Add(this, 252 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, 253 content::NotificationService::AllSources()); 254} 255 256TabHelper::~TabHelper() { 257#if defined(ENABLE_EXTENSIONS) 258 RemoveScriptExecutionObserver(ActivityLog::GetInstance(profile_)); 259#endif 260} 261 262void TabHelper::CreateApplicationShortcuts() { 263 DCHECK(CanCreateApplicationShortcuts()); 264 NavigationEntry* entry = 265 web_contents()->GetController().GetLastCommittedEntry(); 266 if (!entry) 267 return; 268 269 pending_web_app_action_ = CREATE_SHORTCUT; 270 271 // Start fetching web app info for CreateApplicationShortcut dialog and show 272 // the dialog when the data is available in OnDidGetApplicationInfo. 273 GetApplicationInfo(entry->GetPageID()); 274} 275 276void TabHelper::CreateHostedAppFromWebContents() { 277 DCHECK(CanCreateApplicationShortcuts()); 278 NavigationEntry* entry = 279 web_contents()->GetController().GetLastCommittedEntry(); 280 if (!entry) 281 return; 282 283 pending_web_app_action_ = CREATE_HOSTED_APP; 284 285 // Start fetching web app info for CreateApplicationShortcut dialog and show 286 // the dialog when the data is available in OnDidGetApplicationInfo. 287 GetApplicationInfo(entry->GetPageID()); 288} 289 290bool TabHelper::CanCreateApplicationShortcuts() const { 291#if defined(OS_MACOSX) 292 return false; 293#else 294 return web_app::IsValidUrl(web_contents()->GetURL()) && 295 pending_web_app_action_ == NONE; 296#endif 297} 298 299void TabHelper::SetExtensionApp(const Extension* extension) { 300 DCHECK(!extension || AppLaunchInfo::GetFullLaunchURL(extension).is_valid()); 301 if (extension_app_ == extension) 302 return; 303 304 extension_app_ = extension; 305 306 UpdateExtensionAppIcon(extension_app_); 307 308 content::NotificationService::current()->Notify( 309 chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, 310 content::Source<TabHelper>(this), 311 content::NotificationService::NoDetails()); 312} 313 314void TabHelper::SetExtensionAppById(const std::string& extension_app_id) { 315 const Extension* extension = GetExtension(extension_app_id); 316 if (extension) 317 SetExtensionApp(extension); 318} 319 320void TabHelper::SetExtensionAppIconById(const std::string& extension_app_id) { 321 const Extension* extension = GetExtension(extension_app_id); 322 if (extension) 323 UpdateExtensionAppIcon(extension); 324} 325 326SkBitmap* TabHelper::GetExtensionAppIcon() { 327 if (extension_app_icon_.empty()) 328 return NULL; 329 330 return &extension_app_icon_; 331} 332 333void TabHelper::RenderViewCreated(RenderViewHost* render_view_host) { 334 SetTabId(render_view_host); 335} 336 337void TabHelper::DidNavigateMainFrame( 338 const content::LoadCommittedDetails& details, 339 const content::FrameNavigateParams& params) { 340#if defined(ENABLE_EXTENSIONS) 341 if (ExtensionSystem::Get(profile_)->extension_service() && 342 RulesRegistryService::Get(profile_)) { 343 RulesRegistryService::Get(profile_)->content_rules_registry()-> 344 DidNavigateMainFrame(web_contents(), details, params); 345 } 346#endif // defined(ENABLE_EXTENSIONS) 347 348 Profile* profile = 349 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 350 ExtensionService* service = profile->GetExtensionService(); 351 if (!service) 352 return; 353 354 if (CommandLine::ForCurrentProcess()->HasSwitch( 355 switches::kEnableStreamlinedHostedApps)) { 356#if !defined(OS_ANDROID) 357 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); 358 if (browser && browser->is_app()) { 359 SetExtensionApp(service->GetInstalledExtension( 360 web_app::GetExtensionIdFromApplicationName(browser->app_name()))); 361 } else { 362 UpdateExtensionAppIcon(service->GetInstalledExtensionByUrl(params.url)); 363 } 364#endif 365 } else { 366 UpdateExtensionAppIcon(service->GetInstalledExtensionByUrl(params.url)); 367 } 368 369 if (details.is_in_page) 370 return; 371 372 ExtensionActionManager* extension_action_manager = 373 ExtensionActionManager::Get(profile); 374 for (ExtensionSet::const_iterator it = service->extensions()->begin(); 375 it != service->extensions()->end(); ++it) { 376 ExtensionAction* browser_action = 377 extension_action_manager->GetBrowserAction(*it->get()); 378 if (browser_action) { 379 browser_action->ClearAllValuesForTab(SessionID::IdForTab(web_contents())); 380 content::NotificationService::current()->Notify( 381 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, 382 content::Source<ExtensionAction>(browser_action), 383 content::NotificationService::NoDetails()); 384 } 385 } 386} 387 388bool TabHelper::OnMessageReceived(const IPC::Message& message) { 389 bool handled = true; 390 IPC_BEGIN_MESSAGE_MAP(TabHelper, message) 391 IPC_MESSAGE_HANDLER(ExtensionHostMsg_DidGetApplicationInfo, 392 OnDidGetApplicationInfo) 393 IPC_MESSAGE_HANDLER(ExtensionHostMsg_InlineWebstoreInstall, 394 OnInlineWebstoreInstall) 395 IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppInstallState, 396 OnGetAppInstallState); 397 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) 398 IPC_MESSAGE_HANDLER(ExtensionHostMsg_ContentScriptsExecuting, 399 OnContentScriptsExecuting) 400 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange, 401 OnWatchedPageChange) 402 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DetailedConsoleMessageAdded, 403 OnDetailedConsoleMessageAdded) 404 IPC_MESSAGE_UNHANDLED(handled = false) 405 IPC_END_MESSAGE_MAP() 406 return handled; 407} 408 409void TabHelper::CreateHostedApp() { 410 // Add urls from the WebApplicationInfo. 411 std::vector<GURL> web_app_info_icon_urls; 412 for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it = 413 web_app_info_.icons.begin(); 414 it != web_app_info_.icons.end(); ++it) { 415 if (it->url.is_valid()) 416 web_app_info_icon_urls.push_back(it->url); 417 } 418 419 favicon_downloader_.reset( 420 new FaviconDownloader(web_contents(), 421 web_app_info_icon_urls, 422 base::Bind(&TabHelper::FinishCreateHostedApp, 423 base::Unretained(this)))); 424 favicon_downloader_->Start(); 425} 426 427// TODO(calamity): Move hosted app generation into its own file. 428void TabHelper::FinishCreateHostedApp( 429 bool success, 430 const std::map<GURL, std::vector<SkBitmap> >& bitmaps) { 431 // The tab has navigated away during the icon download. Cancel the hosted app 432 // creation. 433 if (!success) { 434 favicon_downloader_.reset(); 435 return; 436 } 437 438 if (web_app_info_.app_url.is_empty()) 439 web_app_info_.app_url = web_contents()->GetURL(); 440 441 if (web_app_info_.title.empty()) 442 web_app_info_.title = web_contents()->GetTitle(); 443 if (web_app_info_.title.empty()) 444 web_app_info_.title = base::UTF8ToUTF16(web_app_info_.app_url.spec()); 445 446 // Add the downloaded icons. Extensions only allow certain icon sizes. First 447 // populate icons that match the allowed sizes exactly and then downscale 448 // remaining icons to the closest allowed size that doesn't yet have an icon. 449 std::set<int> allowed_sizes( 450 extension_misc::kExtensionIconSizes, 451 extension_misc::kExtensionIconSizes + 452 extension_misc::kNumExtensionIconSizes); 453 std::vector<SkBitmap> downloaded_icons; 454 for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin(); 455 map_it != bitmaps.end(); ++map_it) { 456 for (std::vector<SkBitmap>::const_iterator bitmap_it = 457 map_it->second.begin(); 458 bitmap_it != map_it->second.end(); ++bitmap_it) { 459 if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height()) 460 continue; 461 462 downloaded_icons.push_back(*bitmap_it); 463 } 464 } 465 466 // If there are icons that don't match the accepted icon sizes, find the 467 // closest bigger icon to the accepted sizes and resize the icon to it. An 468 // icon will be resized and used for at most one size. 469 std::map<int, SkBitmap> resized_bitmaps( 470 TabHelper::ConstrainBitmapsToSizes(downloaded_icons, 471 allowed_sizes)); 472 473 // Generate container icons from smaller icons. 474 const int kIconSizesToGenerate[] = { 475 extension_misc::EXTENSION_ICON_SMALL, 476 extension_misc::EXTENSION_ICON_MEDIUM, 477 }; 478 const std::set<int> generate_sizes( 479 kIconSizesToGenerate, 480 kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); 481 482 // Only generate icons if larger icons don't exist. This means the app 483 // launcher and the taskbar will do their best downsizing large icons and 484 // these container icons are only generated as a last resort against upscaling 485 // a smaller icon. 486 if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) == 487 resized_bitmaps.end()) { 488 // Generate these from biggest to smallest so we don't end up with 489 // concentric container icons. 490 for (std::set<int>::const_reverse_iterator it = generate_sizes.rbegin(); 491 it != generate_sizes.rend(); ++it) { 492 TabHelper::GenerateContainerIcon(&resized_bitmaps, *it); 493 } 494 } 495 496 // Populate a the icon data into the WebApplicationInfo we are using to 497 // install the bookmark app. 498 for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it = 499 resized_bitmaps.begin(); 500 resized_bitmaps_it != resized_bitmaps.end(); ++resized_bitmaps_it) { 501 WebApplicationInfo::IconInfo icon_info; 502 icon_info.data = resized_bitmaps_it->second; 503 icon_info.width = icon_info.data.width(); 504 icon_info.height = icon_info.data.height(); 505 web_app_info_.icons.push_back(icon_info); 506 } 507 508 // Install the app. 509 Profile* profile = 510 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 511 scoped_refptr<extensions::CrxInstaller> installer( 512 extensions::CrxInstaller::CreateSilent(profile->GetExtensionService())); 513 installer->set_error_on_unsupported_requirements(true); 514 installer->InstallWebApp(web_app_info_); 515 favicon_downloader_.reset(); 516} 517 518void TabHelper::DidCloneToNewWebContents(WebContents* old_web_contents, 519 WebContents* new_web_contents) { 520 // When the WebContents that this is attached to is cloned, give the new clone 521 // a TabHelper and copy state over. 522 CreateForWebContents(new_web_contents); 523 TabHelper* new_helper = FromWebContents(new_web_contents); 524 525 new_helper->SetExtensionApp(extension_app()); 526 new_helper->extension_app_icon_ = extension_app_icon_; 527} 528 529void TabHelper::OnDidGetApplicationInfo(int32 page_id, 530 const WebApplicationInfo& info) { 531 // Android does not implement BrowserWindow. 532#if !defined(OS_MACOSX) && !defined(OS_ANDROID) 533 web_app_info_ = info; 534 535 NavigationEntry* entry = 536 web_contents()->GetController().GetLastCommittedEntry(); 537 if (!entry || (entry->GetPageID() != page_id)) 538 return; 539 540 switch (pending_web_app_action_) { 541 case CREATE_SHORTCUT: { 542 chrome::ShowCreateWebAppShortcutsDialog( 543 web_contents()->GetView()->GetTopLevelNativeWindow(), 544 web_contents()); 545 break; 546 } 547 case CREATE_HOSTED_APP: { 548 CreateHostedApp(); 549 break; 550 } 551 case UPDATE_SHORTCUT: { 552 web_app::UpdateShortcutForTabContents(web_contents()); 553 break; 554 } 555 default: 556 NOTREACHED(); 557 break; 558 } 559 560 // The hosted app action will be cleared once the installation completes or 561 // fails. 562 if (pending_web_app_action_ != CREATE_HOSTED_APP) 563 pending_web_app_action_ = NONE; 564#endif 565} 566 567void TabHelper::OnInlineWebstoreInstall( 568 int install_id, 569 int return_route_id, 570 const std::string& webstore_item_id, 571 const GURL& requestor_url) { 572 WebstoreStandaloneInstaller::Callback callback = 573 base::Bind(&TabHelper::OnInlineInstallComplete, base::Unretained(this), 574 install_id, return_route_id); 575 scoped_refptr<WebstoreInlineInstaller> installer( 576 webstore_inline_installer_factory_->CreateInstaller( 577 web_contents(), 578 webstore_item_id, 579 requestor_url, 580 callback)); 581 installer->BeginInstall(); 582} 583 584void TabHelper::OnGetAppInstallState(const GURL& requestor_url, 585 int return_route_id, 586 int callback_id) { 587 ExtensionRegistry* registry = 588 ExtensionRegistry::Get(web_contents()->GetBrowserContext()); 589 const ExtensionSet& extensions = registry->enabled_extensions(); 590 const ExtensionSet& disabled_extensions = registry->disabled_extensions(); 591 592 std::string state; 593 if (extensions.GetHostedAppByURL(requestor_url)) 594 state = extension_misc::kAppStateInstalled; 595 else if (disabled_extensions.GetHostedAppByURL(requestor_url)) 596 state = extension_misc::kAppStateDisabled; 597 else 598 state = extension_misc::kAppStateNotInstalled; 599 600 Send(new ExtensionMsg_GetAppInstallStateResponse( 601 return_route_id, state, callback_id)); 602} 603 604void TabHelper::OnRequest(const ExtensionHostMsg_Request_Params& request) { 605 extension_function_dispatcher_.Dispatch(request, 606 web_contents()->GetRenderViewHost()); 607} 608 609void TabHelper::OnContentScriptsExecuting( 610 const ScriptExecutionObserver::ExecutingScriptsMap& executing_scripts_map, 611 int32 on_page_id, 612 const GURL& on_url) { 613 FOR_EACH_OBSERVER(ScriptExecutionObserver, script_execution_observers_, 614 OnScriptsExecuted(web_contents(), 615 executing_scripts_map, 616 on_page_id, 617 on_url)); 618} 619 620void TabHelper::OnWatchedPageChange( 621 const std::vector<std::string>& css_selectors) { 622#if defined(ENABLE_EXTENSIONS) 623 if (ExtensionSystem::Get(profile_)->extension_service() && 624 RulesRegistryService::Get(profile_)) { 625 RulesRegistryService::Get(profile_)->content_rules_registry()->Apply( 626 web_contents(), css_selectors); 627 } 628#endif // defined(ENABLE_EXTENSIONS) 629} 630 631void TabHelper::OnDetailedConsoleMessageAdded( 632 const base::string16& message, 633 const base::string16& source, 634 const StackTrace& stack_trace, 635 int32 severity_level) { 636 if (IsSourceFromAnExtension(source)) { 637 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); 638 ErrorConsole::Get(profile_)->ReportError( 639 scoped_ptr<ExtensionError>(new RuntimeError( 640 extension_app_ ? extension_app_->id() : std::string(), 641 profile_->IsOffTheRecord(), 642 source, 643 message, 644 stack_trace, 645 web_contents() ? 646 web_contents()->GetLastCommittedURL() : GURL::EmptyGURL(), 647 static_cast<logging::LogSeverity>(severity_level), 648 rvh->GetRoutingID(), 649 rvh->GetProcess()->GetID()))); 650 } 651} 652 653const Extension* TabHelper::GetExtension(const std::string& extension_app_id) { 654 if (extension_app_id.empty()) 655 return NULL; 656 657 Profile* profile = 658 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 659 ExtensionService* extension_service = profile->GetExtensionService(); 660 if (!extension_service || !extension_service->is_ready()) 661 return NULL; 662 663 const Extension* extension = 664 extension_service->GetExtensionById(extension_app_id, false); 665 return extension; 666} 667 668void TabHelper::UpdateExtensionAppIcon(const Extension* extension) { 669 extension_app_icon_.reset(); 670 // Ensure previously enqueued callbacks are ignored. 671 image_loader_ptr_factory_.InvalidateWeakPtrs(); 672 673 // Enqueue OnImageLoaded callback. 674 if (extension) { 675 Profile* profile = 676 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 677 extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile); 678 loader->LoadImageAsync( 679 extension, 680 IconsInfo::GetIconResource(extension, 681 extension_misc::EXTENSION_ICON_SMALL, 682 ExtensionIconSet::MATCH_BIGGER), 683 gfx::Size(extension_misc::EXTENSION_ICON_SMALL, 684 extension_misc::EXTENSION_ICON_SMALL), 685 base::Bind(&TabHelper::OnImageLoaded, 686 image_loader_ptr_factory_.GetWeakPtr())); 687 } 688} 689 690void TabHelper::SetAppIcon(const SkBitmap& app_icon) { 691 extension_app_icon_ = app_icon; 692 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE); 693} 694 695void TabHelper::SetWebstoreInlineInstallerFactoryForTests( 696 WebstoreInlineInstallerFactory* factory) { 697 webstore_inline_installer_factory_.reset(factory); 698} 699 700void TabHelper::OnImageLoaded(const gfx::Image& image) { 701 if (!image.IsEmpty()) { 702 extension_app_icon_ = *image.ToSkBitmap(); 703 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); 704 } 705} 706 707WindowController* TabHelper::GetExtensionWindowController() const { 708 return ExtensionTabUtil::GetWindowControllerOfTab(web_contents()); 709} 710 711void TabHelper::OnInlineInstallComplete(int install_id, 712 int return_route_id, 713 bool success, 714 const std::string& error) { 715 Send(new ExtensionMsg_InlineWebstoreInstallResponse( 716 return_route_id, install_id, success, success ? std::string() : error)); 717} 718 719WebContents* TabHelper::GetAssociatedWebContents() const { 720 return web_contents(); 721} 722 723void TabHelper::GetApplicationInfo(int32 page_id) { 724 Send(new ExtensionMsg_GetApplicationInfo(routing_id(), page_id)); 725} 726 727void TabHelper::Observe(int type, 728 const content::NotificationSource& source, 729 const content::NotificationDetails& details) { 730 switch (type) { 731 case content::NOTIFICATION_LOAD_STOP: { 732 const NavigationController& controller = 733 *content::Source<NavigationController>(source).ptr(); 734 DCHECK_EQ(controller.GetWebContents(), web_contents()); 735 736 if (pending_web_app_action_ == UPDATE_SHORTCUT) { 737 // Schedule a shortcut update when web application info is available if 738 // last committed entry is not NULL. Last committed entry could be NULL 739 // when an interstitial page is injected (e.g. bad https certificate, 740 // malware site etc). When this happens, we abort the shortcut update. 741 NavigationEntry* entry = controller.GetLastCommittedEntry(); 742 if (entry) 743 GetApplicationInfo(entry->GetPageID()); 744 else 745 pending_web_app_action_ = NONE; 746 } 747 break; 748 } 749 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: { 750 if (pending_web_app_action_ != CREATE_HOSTED_APP) 751 return; 752 753 pending_web_app_action_ = NONE; 754 755 const Extension* extension = 756 content::Details<const Extension>(details).ptr(); 757 if (!extension || 758 AppLaunchInfo::GetLaunchWebURL(extension) != web_app_info_.app_url) 759 return; 760 761#if defined(OS_CHROMEOS) 762 ChromeLauncherController::instance()->PinAppWithID(extension->id()); 763#endif 764 765 // Android does not implement browser_finder.cc. 766#if !defined(OS_ANDROID) 767 Browser* browser = 768 chrome::FindBrowserWithWebContents(web_contents()); 769 if (browser) { 770 browser->window()->ShowBookmarkAppBubble(web_app_info_, 771 extension->id()); 772 } 773#endif 774 } 775 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: { 776 if (pending_web_app_action_ == CREATE_HOSTED_APP) 777 pending_web_app_action_ = NONE; 778 break; 779 } 780 } 781} 782 783void TabHelper::SetTabId(RenderViewHost* render_view_host) { 784 render_view_host->Send( 785 new ExtensionMsg_SetTabId(render_view_host->GetRoutingID(), 786 SessionID::IdForTab(web_contents()))); 787} 788 789} // namespace extensions 790