Home | History | Annotate | Download | only in browser
      1 // Copyright 2013 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 "content/shell/browser/shell.h"
      6 
      7 #include "base/auto_reset.h"
      8 #include "base/command_line.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/path_service.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "content/public/browser/devtools_agent_host.h"
     16 #include "content/public/browser/navigation_controller.h"
     17 #include "content/public/browser/navigation_entry.h"
     18 #include "content/public/browser/render_view_host.h"
     19 #include "content/public/browser/web_contents.h"
     20 #include "content/public/browser/web_contents_observer.h"
     21 #include "content/public/common/renderer_preferences.h"
     22 #include "content/shell/browser/notify_done_forwarder.h"
     23 #include "content/shell/browser/shell_browser_main_parts.h"
     24 #include "content/shell/browser/shell_content_browser_client.h"
     25 #include "content/shell/browser/shell_devtools_frontend.h"
     26 #include "content/shell/browser/shell_javascript_dialog_manager.h"
     27 #include "content/shell/browser/webkit_test_controller.h"
     28 #include "content/shell/common/shell_messages.h"
     29 #include "content/shell/common/shell_switches.h"
     30 
     31 namespace content {
     32 
     33 const int Shell::kDefaultTestWindowWidthDip = 800;
     34 const int Shell::kDefaultTestWindowHeightDip = 600;
     35 
     36 std::vector<Shell*> Shell::windows_;
     37 base::Callback<void(Shell*)> Shell::shell_created_callback_;
     38 
     39 bool Shell::quit_message_loop_ = true;
     40 
     41 class Shell::DevToolsWebContentsObserver : public WebContentsObserver {
     42  public:
     43   DevToolsWebContentsObserver(Shell* shell, WebContents* web_contents)
     44       : WebContentsObserver(web_contents),
     45         shell_(shell) {
     46   }
     47 
     48   // WebContentsObserver
     49   virtual void WebContentsDestroyed() OVERRIDE {
     50     shell_->OnDevToolsWebContentsDestroyed();
     51   }
     52 
     53  private:
     54   Shell* shell_;
     55 
     56   DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
     57 };
     58 
     59 Shell::Shell(WebContents* web_contents)
     60     : WebContentsObserver(web_contents),
     61       devtools_frontend_(NULL),
     62       is_fullscreen_(false),
     63       window_(NULL),
     64       url_edit_view_(NULL),
     65       headless_(false) {
     66   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
     67   if (command_line.HasSwitch(switches::kDumpRenderTree))
     68     headless_ = true;
     69   windows_.push_back(this);
     70 
     71   if (!shell_created_callback_.is_null()) {
     72     shell_created_callback_.Run(this);
     73     shell_created_callback_.Reset();
     74   }
     75 }
     76 
     77 Shell::~Shell() {
     78   PlatformCleanUp();
     79 
     80   for (size_t i = 0; i < windows_.size(); ++i) {
     81     if (windows_[i] == this) {
     82       windows_.erase(windows_.begin() + i);
     83       break;
     84     }
     85   }
     86 
     87   if (windows_.empty() && quit_message_loop_) {
     88     if (headless_)
     89       PlatformExit();
     90     base::MessageLoop::current()->PostTask(FROM_HERE,
     91                                            base::MessageLoop::QuitClosure());
     92   }
     93 }
     94 
     95 Shell* Shell::CreateShell(WebContents* web_contents,
     96                           const gfx::Size& initial_size) {
     97   Shell* shell = new Shell(web_contents);
     98   shell->PlatformCreateWindow(initial_size.width(), initial_size.height());
     99 
    100   shell->web_contents_.reset(web_contents);
    101   web_contents->SetDelegate(shell);
    102 
    103   shell->PlatformSetContents();
    104 
    105   shell->PlatformResizeSubViews();
    106 
    107   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
    108     web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
    109     web_contents->GetRenderViewHost()->SyncRendererPrefs();
    110   }
    111 
    112   return shell;
    113 }
    114 
    115 void Shell::CloseAllWindows() {
    116   base::AutoReset<bool> auto_reset(&quit_message_loop_, false);
    117   DevToolsAgentHost::DetachAllClients();
    118   std::vector<Shell*> open_windows(windows_);
    119   for (size_t i = 0; i < open_windows.size(); ++i)
    120     open_windows[i]->Close();
    121   PlatformExit();
    122   base::MessageLoop::current()->RunUntilIdle();
    123 }
    124 
    125 void Shell::SetShellCreatedCallback(
    126     base::Callback<void(Shell*)> shell_created_callback) {
    127   DCHECK(shell_created_callback_.is_null());
    128   shell_created_callback_ = shell_created_callback;
    129 }
    130 
    131 Shell* Shell::FromRenderViewHost(RenderViewHost* rvh) {
    132   for (size_t i = 0; i < windows_.size(); ++i) {
    133     if (windows_[i]->web_contents() &&
    134         windows_[i]->web_contents()->GetRenderViewHost() == rvh) {
    135       return windows_[i];
    136     }
    137   }
    138   return NULL;
    139 }
    140 
    141 // static
    142 void Shell::Initialize() {
    143   PlatformInitialize(
    144       gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip));
    145 }
    146 
    147 gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) {
    148   if (!initial_size.IsEmpty())
    149     return initial_size;
    150   return gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
    151 }
    152 
    153 Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
    154                               const GURL& url,
    155                               SiteInstance* site_instance,
    156                               int routing_id,
    157                               const gfx::Size& initial_size) {
    158   WebContents::CreateParams create_params(browser_context, site_instance);
    159   create_params.routing_id = routing_id;
    160   create_params.initial_size = AdjustWindowSize(initial_size);
    161   WebContents* web_contents = WebContents::Create(create_params);
    162   Shell* shell = CreateShell(web_contents, create_params.initial_size);
    163   if (!url.is_empty())
    164     shell->LoadURL(url);
    165   return shell;
    166 }
    167 
    168 void Shell::LoadURL(const GURL& url) {
    169   LoadURLForFrame(url, std::string());
    170 }
    171 
    172 void Shell::LoadURLForFrame(const GURL& url, const std::string& frame_name) {
    173   NavigationController::LoadURLParams params(url);
    174   params.transition_type = ui::PageTransitionFromInt(
    175       ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
    176   params.frame_name = frame_name;
    177   web_contents_->GetController().LoadURLWithParams(params);
    178   web_contents_->Focus();
    179 }
    180 
    181 void Shell::LoadDataWithBaseURL(const GURL& url, const std::string& data,
    182     const GURL& base_url) {
    183   const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
    184   NavigationController::LoadURLParams params(data_url);
    185   params.load_type = NavigationController::LOAD_TYPE_DATA;
    186   params.base_url_for_data_url = base_url;
    187   params.virtual_url_for_data_url = url;
    188   params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
    189   web_contents_->GetController().LoadURLWithParams(params);
    190   web_contents_->Focus();
    191 }
    192 
    193 void Shell::AddNewContents(WebContents* source,
    194                            WebContents* new_contents,
    195                            WindowOpenDisposition disposition,
    196                            const gfx::Rect& initial_pos,
    197                            bool user_gesture,
    198                            bool* was_blocked) {
    199   CreateShell(new_contents, AdjustWindowSize(initial_pos.size()));
    200   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
    201     NotifyDoneForwarder::CreateForWebContents(new_contents);
    202 }
    203 
    204 void Shell::GoBackOrForward(int offset) {
    205   web_contents_->GetController().GoToOffset(offset);
    206   web_contents_->Focus();
    207 }
    208 
    209 void Shell::Reload() {
    210   web_contents_->GetController().Reload(false);
    211   web_contents_->Focus();
    212 }
    213 
    214 void Shell::Stop() {
    215   web_contents_->Stop();
    216   web_contents_->Focus();
    217 }
    218 
    219 void Shell::UpdateNavigationControls(bool to_different_document) {
    220   int current_index = web_contents_->GetController().GetCurrentEntryIndex();
    221   int max_index = web_contents_->GetController().GetEntryCount() - 1;
    222 
    223   PlatformEnableUIControl(BACK_BUTTON, current_index > 0);
    224   PlatformEnableUIControl(FORWARD_BUTTON, current_index < max_index);
    225   PlatformEnableUIControl(STOP_BUTTON,
    226       to_different_document && web_contents_->IsLoading());
    227 }
    228 
    229 void Shell::ShowDevTools() {
    230   InnerShowDevTools("", "");
    231 }
    232 
    233 void Shell::ShowDevToolsForElementAt(int x, int y) {
    234   InnerShowDevTools("", "");
    235   devtools_frontend_->InspectElementAt(x, y);
    236 }
    237 
    238 void Shell::ShowDevToolsForTest(const std::string& settings,
    239                                 const std::string& frontend_url) {
    240   InnerShowDevTools(settings, frontend_url);
    241 }
    242 
    243 void Shell::CloseDevTools() {
    244   if (!devtools_frontend_)
    245     return;
    246   devtools_observer_.reset();
    247   devtools_frontend_->Close();
    248   devtools_frontend_ = NULL;
    249 }
    250 
    251 gfx::NativeView Shell::GetContentView() {
    252   if (!web_contents_)
    253     return NULL;
    254   return web_contents_->GetNativeView();
    255 }
    256 
    257 WebContents* Shell::OpenURLFromTab(WebContents* source,
    258                                    const OpenURLParams& params) {
    259   // CURRENT_TAB is the only one we implement for now.
    260   if (params.disposition != CURRENT_TAB)
    261       return NULL;
    262   NavigationController::LoadURLParams load_url_params(params.url);
    263   load_url_params.referrer = params.referrer;
    264   load_url_params.frame_tree_node_id = params.frame_tree_node_id;
    265   load_url_params.transition_type = params.transition;
    266   load_url_params.extra_headers = params.extra_headers;
    267   load_url_params.should_replace_current_entry =
    268       params.should_replace_current_entry;
    269 
    270   if (params.transferred_global_request_id != GlobalRequestID()) {
    271     load_url_params.is_renderer_initiated = params.is_renderer_initiated;
    272     load_url_params.transferred_global_request_id =
    273         params.transferred_global_request_id;
    274   } else if (params.is_renderer_initiated) {
    275     load_url_params.is_renderer_initiated = true;
    276   }
    277 
    278   source->GetController().LoadURLWithParams(load_url_params);
    279   return source;
    280 }
    281 
    282 void Shell::LoadingStateChanged(WebContents* source,
    283     bool to_different_document) {
    284   UpdateNavigationControls(to_different_document);
    285   PlatformSetIsLoading(source->IsLoading());
    286 }
    287 
    288 void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
    289                                        bool enter_fullscreen) {
    290 #if defined(OS_ANDROID)
    291   PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen);
    292 #endif
    293   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
    294     return;
    295   if (is_fullscreen_ != enter_fullscreen) {
    296     is_fullscreen_ = enter_fullscreen;
    297     web_contents->GetRenderViewHost()->WasResized();
    298   }
    299 }
    300 
    301 bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const {
    302 #if defined(OS_ANDROID)
    303   return PlatformIsFullscreenForTabOrPending(web_contents);
    304 #else
    305   return is_fullscreen_;
    306 #endif
    307 }
    308 
    309 void Shell::RequestToLockMouse(WebContents* web_contents,
    310                                bool user_gesture,
    311                                bool last_unlocked_by_target) {
    312   web_contents->GotResponseToLockMouseRequest(true);
    313 }
    314 
    315 void Shell::CloseContents(WebContents* source) {
    316   Close();
    317 }
    318 
    319 bool Shell::CanOverscrollContent() const {
    320 #if defined(USE_AURA)
    321   return true;
    322 #else
    323   return false;
    324 #endif
    325 }
    326 
    327 void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) {
    328   PlatformSetAddressBarURL(web_contents->GetLastCommittedURL());
    329 }
    330 
    331 JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() {
    332   if (!dialog_manager_)
    333     dialog_manager_.reset(new ShellJavaScriptDialogManager());
    334   return dialog_manager_.get();
    335 }
    336 
    337 bool Shell::AddMessageToConsole(WebContents* source,
    338                                 int32 level,
    339                                 const base::string16& message,
    340                                 int32 line_no,
    341                                 const base::string16& source_id) {
    342   return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
    343 }
    344 
    345 void Shell::RendererUnresponsive(WebContents* source) {
    346   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
    347     return;
    348   WebKitTestController::Get()->RendererUnresponsive();
    349 }
    350 
    351 void Shell::ActivateContents(WebContents* contents) {
    352   contents->GetRenderViewHost()->Focus();
    353 }
    354 
    355 void Shell::DeactivateContents(WebContents* contents) {
    356   contents->GetRenderViewHost()->Blur();
    357 }
    358 
    359 void Shell::WorkerCrashed(WebContents* source) {
    360   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
    361     return;
    362   WebKitTestController::Get()->WorkerCrashed();
    363 }
    364 
    365 bool Shell::HandleContextMenu(const content::ContextMenuParams& params) {
    366   return PlatformHandleContextMenu(params);
    367 }
    368 
    369 void Shell::WebContentsFocused(WebContents* contents) {
    370 #if defined(TOOLKIT_VIEWS)
    371   PlatformWebContentsFocused(contents);
    372 #endif
    373 }
    374 
    375 void Shell::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
    376   if (entry)
    377     PlatformSetTitle(entry->GetTitle());
    378 }
    379 
    380 void Shell::InnerShowDevTools(const std::string& settings,
    381                               const std::string& frontend_url) {
    382   if (!devtools_frontend_) {
    383     devtools_frontend_ = ShellDevToolsFrontend::Show(
    384         web_contents(), settings, frontend_url);
    385     devtools_observer_.reset(new DevToolsWebContentsObserver(
    386         this, devtools_frontend_->frontend_shell()->web_contents()));
    387   }
    388 
    389   devtools_frontend_->Activate();
    390   devtools_frontend_->Focus();
    391 }
    392 
    393 void Shell::OnDevToolsWebContentsDestroyed() {
    394   devtools_observer_.reset();
    395   devtools_frontend_ = NULL;
    396 }
    397 
    398 }  // namespace content
    399