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