1// Copyright 2014 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/chrome_extension_function_details.h"
6
7#include "chrome/browser/extensions/window_controller.h"
8#include "chrome/browser/extensions/window_controller_list.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/ui/browser.h"
11#include "chrome/browser/ui/browser_finder.h"
12#include "chrome/browser/ui/tabs/tab_strip_model.h"
13#include "content/public/browser/render_process_host.h"
14#include "content/public/browser/render_view_host.h"
15#include "extensions/browser/extension_function.h"
16#include "extensions/browser/extension_function_dispatcher.h"
17
18using content::WebContents;
19using content::RenderViewHost;
20using extensions::WindowController;
21
22ChromeExtensionFunctionDetails::ChromeExtensionFunctionDetails(
23    UIThreadExtensionFunction* function)
24    : function_(function) {
25}
26
27ChromeExtensionFunctionDetails::~ChromeExtensionFunctionDetails() {
28}
29
30Profile* ChromeExtensionFunctionDetails::GetProfile() const {
31  return Profile::FromBrowserContext(function_->browser_context());
32}
33
34bool ChromeExtensionFunctionDetails::CanOperateOnWindow(
35    const extensions::WindowController* window_controller) const {
36  // |extension()| is NULL for unit tests only.
37  if (function_->extension() != NULL &&
38      !window_controller->IsVisibleToExtension(function_->extension())) {
39    return false;
40  }
41
42  if (GetProfile() == window_controller->profile())
43    return true;
44
45  if (!function_->include_incognito())
46    return false;
47
48  return GetProfile()->HasOffTheRecordProfile() &&
49         GetProfile()->GetOffTheRecordProfile() == window_controller->profile();
50}
51
52// TODO(stevenjb): Replace this with GetExtensionWindowController().
53Browser* ChromeExtensionFunctionDetails::GetCurrentBrowser() const {
54  // If the delegate has an associated browser, return it.
55  if (function_->dispatcher()) {
56    extensions::WindowController* window_controller =
57        function_->dispatcher()->delegate()->GetExtensionWindowController();
58    if (window_controller) {
59      Browser* browser = window_controller->GetBrowser();
60      if (browser)
61        return browser;
62    }
63  }
64
65  // Otherwise, try to default to a reasonable browser. If |include_incognito_|
66  // is true, we will also search browsers in the incognito version of this
67  // profile. Note that the profile may already be incognito, in which case
68  // we will search the incognito version only, regardless of the value of
69  // |include_incognito|. Look only for browsers on the active desktop as it is
70  // preferable to pretend no browser is open then to return a browser on
71  // another desktop.
72  if (function_->render_view_host()) {
73    Profile* profile = Profile::FromBrowserContext(
74        function_->render_view_host()->GetProcess()->GetBrowserContext());
75    Browser* browser = chrome::FindAnyBrowser(
76        profile, function_->include_incognito(), chrome::GetActiveDesktop());
77    if (browser)
78      return browser;
79  }
80
81  // NOTE(rafaelw): This can return NULL in some circumstances. In particular,
82  // a background_page onload chrome.tabs api call can make it into here
83  // before the browser is sufficiently initialized to return here, or
84  // all of this profile's browser windows may have been closed.
85  // A similar situation may arise during shutdown.
86  // TODO(rafaelw): Delay creation of background_page until the browser
87  // is available. http://code.google.com/p/chromium/issues/detail?id=13284
88  return NULL;
89}
90
91extensions::WindowController*
92ChromeExtensionFunctionDetails::GetExtensionWindowController() const {
93  // If the delegate has an associated window controller, return it.
94  if (function_->dispatcher()) {
95    extensions::WindowController* window_controller =
96        function_->dispatcher()->delegate()->GetExtensionWindowController();
97    if (window_controller)
98      return window_controller;
99  }
100
101  return extensions::WindowControllerList::GetInstance()
102      ->CurrentWindowForFunction(*this);
103}
104
105content::WebContents*
106ChromeExtensionFunctionDetails::GetAssociatedWebContents() {
107  content::WebContents* web_contents = function_->GetAssociatedWebContents();
108  if (web_contents)
109    return web_contents;
110
111  Browser* browser = GetCurrentBrowser();
112  if (!browser)
113    return NULL;
114  return browser->tab_strip_model()->GetActiveWebContents();
115}
116