| OLD | NEW |
| (Empty) |
| 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/external_tab_container_win.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/bind_helpers.h" | |
| 11 #include "base/debug/trace_event.h" | |
| 12 #include "base/i18n/rtl.h" | |
| 13 #include "base/logging.h" | |
| 14 #include "base/memory/scoped_ptr.h" | |
| 15 #include "base/utf_string_conversions.h" | |
| 16 #include "base/win/win_util.h" | |
| 17 #include "chrome/app/chrome_command_ids.h" | |
| 18 #include "chrome/app/chrome_dll_resource.h" | |
| 19 #include "chrome/browser/automation/automation_provider.h" | |
| 20 #include "chrome/browser/debugger/devtools_toggle_action.h" | |
| 21 #include "chrome/browser/debugger/devtools_window.h" | |
| 22 #include "chrome/browser/history/history_tab_helper.h" | |
| 23 #include "chrome/browser/history/history_types.h" | |
| 24 #include "chrome/browser/infobars/infobar_tab_helper.h" | |
| 25 #include "chrome/browser/profiles/profile.h" | |
| 26 #include "chrome/browser/repost_form_warning_controller.h" | |
| 27 #include "chrome/browser/themes/theme_service.h" | |
| 28 #include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h" | |
| 29 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h" | |
| 30 #include "chrome/browser/ui/browser.h" | |
| 31 #include "chrome/browser/ui/browser_dialogs.h" | |
| 32 #include "chrome/browser/ui/browser_window.h" | |
| 33 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | |
| 34 #include "chrome/browser/ui/views/browser_dialogs.h" | |
| 35 #include "chrome/browser/ui/views/infobars/infobar_container_view.h" | |
| 36 #include "chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h" | |
| 37 #include "chrome/browser/ui/views/tab_contents/tab_contents_container.h" | |
| 38 #include "chrome/common/automation_messages.h" | |
| 39 #include "chrome/common/chrome_constants.h" | |
| 40 #include "chrome/common/chrome_notification_types.h" | |
| 41 #include "chrome/common/render_messages.h" | |
| 42 #include "chrome/common/url_constants.h" | |
| 43 #include "content/public/browser/load_notification_details.h" | |
| 44 #include "content/public/browser/native_web_keyboard_event.h" | |
| 45 #include "content/public/browser/navigation_details.h" | |
| 46 #include "content/public/browser/navigation_entry.h" | |
| 47 #include "content/public/browser/notification_service.h" | |
| 48 #include "content/public/browser/render_process_host.h" | |
| 49 #include "content/public/browser/render_view_host.h" | |
| 50 #include "content/public/browser/web_contents.h" | |
| 51 #include "content/public/browser/web_intents_dispatcher.h" | |
| 52 #include "content/public/common/bindings_policy.h" | |
| 53 #include "content/public/common/frame_navigate_params.h" | |
| 54 #include "content/public/common/page_transition_types.h" | |
| 55 #include "content/public/common/page_zoom.h" | |
| 56 #include "content/public/common/renderer_preferences.h" | |
| 57 #include "content/public/common/ssl_status.h" | |
| 58 #include "grit/generated_resources.h" | |
| 59 #include "grit/locale_settings.h" | |
| 60 #include "third_party/WebKit/Source/WebKit/chromium/public/WebReferrerPolicy.h" | |
| 61 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h" | |
| 62 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h
" | |
| 63 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" | |
| 64 #include "ui/base/l10n/l10n_util.h" | |
| 65 #include "ui/base/models/menu_model.h" | |
| 66 #include "ui/base/view_prop.h" | |
| 67 #include "ui/views/layout/grid_layout.h" | |
| 68 | |
| 69 using content::BrowserThread; | |
| 70 using content::LoadNotificationDetails; | |
| 71 using content::NavigationController; | |
| 72 using content::NavigationEntry; | |
| 73 using content::OpenURLParams; | |
| 74 using content::RenderViewHost; | |
| 75 using content::SSLStatus; | |
| 76 using content::WebContents; | |
| 77 using ui::ViewProp; | |
| 78 using WebKit::WebCString; | |
| 79 using WebKit::WebReferrerPolicy; | |
| 80 using WebKit::WebSecurityPolicy; | |
| 81 using WebKit::WebString; | |
| 82 | |
| 83 static const char kWindowObjectKey[] = "ChromeWindowObject"; | |
| 84 | |
| 85 namespace { | |
| 86 | |
| 87 // Convert ui::MenuModel into a serializable form for Chrome Frame | |
| 88 ContextMenuModel* ConvertMenuModel(const ui::MenuModel* ui_model) { | |
| 89 ContextMenuModel* new_model = new ContextMenuModel; | |
| 90 | |
| 91 const int index_base = ui_model->GetFirstItemIndex(NULL); | |
| 92 const int item_count = ui_model->GetItemCount(); | |
| 93 new_model->items.reserve(item_count); | |
| 94 for (int i = 0; i < item_count; ++i) { | |
| 95 const int index = index_base + i; | |
| 96 if (ui_model->IsVisibleAt(index)) { | |
| 97 ContextMenuModel::Item item; | |
| 98 item.type = ui_model->GetTypeAt(index); | |
| 99 item.item_id = ui_model->GetCommandIdAt(index); | |
| 100 item.label = ui_model->GetLabelAt(index); | |
| 101 item.checked = ui_model->IsItemCheckedAt(index); | |
| 102 item.enabled = ui_model->IsEnabledAt(index); | |
| 103 if (item.type == ui::MenuModel::TYPE_SUBMENU) | |
| 104 item.submenu = ConvertMenuModel(ui_model->GetSubmenuModelAt(index)); | |
| 105 | |
| 106 new_model->items.push_back(item); | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 return new_model; | |
| 111 } | |
| 112 | |
| 113 } // namespace | |
| 114 | |
| 115 base::LazyInstance<ExternalTabContainer::PendingTabs> | |
| 116 ExternalTabContainer::pending_tabs_ = LAZY_INSTANCE_INITIALIZER; | |
| 117 | |
| 118 ExternalTabContainer::ExternalTabContainer( | |
| 119 AutomationProvider* automation, AutomationResourceMessageFilter* filter) | |
| 120 : views::NativeWidgetWin(new views::Widget), | |
| 121 automation_(automation), | |
| 122 tab_contents_container_(NULL), | |
| 123 tab_handle_(0), | |
| 124 ignore_next_load_notification_(false), | |
| 125 automation_resource_message_filter_(filter), | |
| 126 load_requests_via_automation_(false), | |
| 127 handle_top_level_requests_(false), | |
| 128 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | |
| 129 pending_(false), | |
| 130 focus_manager_(NULL), | |
| 131 external_tab_view_(NULL), | |
| 132 unload_reply_message_(NULL), | |
| 133 route_all_top_level_navigations_(false), | |
| 134 is_popup_window_(false) { | |
| 135 } | |
| 136 | |
| 137 ExternalTabContainer::~ExternalTabContainer() { | |
| 138 Uninitialize(); | |
| 139 } | |
| 140 | |
| 141 WebContents * ExternalTabContainer::web_contents() const { | |
| 142 return tab_contents_.get() ? tab_contents_->web_contents() : NULL; | |
| 143 } | |
| 144 | |
| 145 bool ExternalTabContainer::Init(Profile* profile, | |
| 146 HWND parent, | |
| 147 const gfx::Rect& bounds, | |
| 148 DWORD style, | |
| 149 bool load_requests_via_automation, | |
| 150 bool handle_top_level_requests, | |
| 151 TabContentsWrapper* existing_contents, | |
| 152 const GURL& initial_url, | |
| 153 const GURL& referrer, | |
| 154 bool infobars_enabled, | |
| 155 bool route_all_top_level_navigations) { | |
| 156 if (IsWindow()) { | |
| 157 NOTREACHED(); | |
| 158 return false; | |
| 159 } | |
| 160 | |
| 161 load_requests_via_automation_ = load_requests_via_automation; | |
| 162 handle_top_level_requests_ = handle_top_level_requests; | |
| 163 route_all_top_level_navigations_ = route_all_top_level_navigations; | |
| 164 | |
| 165 set_window_style(WS_POPUP | WS_CLIPCHILDREN); | |
| 166 | |
| 167 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | |
| 168 params.bounds = bounds; | |
| 169 params.native_widget = this; | |
| 170 GetWidget()->Init(params); | |
| 171 if (!IsWindow()) { | |
| 172 NOTREACHED(); | |
| 173 return false; | |
| 174 } | |
| 175 | |
| 176 // TODO(jcampan): limit focus traversal to contents. | |
| 177 | |
| 178 prop_.reset(new ViewProp(GetNativeView(), kWindowObjectKey, this)); | |
| 179 | |
| 180 if (existing_contents) { | |
| 181 tab_contents_.reset(existing_contents); | |
| 182 tab_contents_->web_contents()->GetController().SetBrowserContext(profile); | |
| 183 } else { | |
| 184 WebContents* new_contents = WebContents::Create( | |
| 185 profile, NULL, MSG_ROUTING_NONE, NULL, NULL); | |
| 186 tab_contents_.reset(new TabContentsWrapper(new_contents)); | |
| 187 } | |
| 188 | |
| 189 if (!infobars_enabled) | |
| 190 tab_contents_->infobar_tab_helper()->set_infobars_enabled(false); | |
| 191 | |
| 192 tab_contents_->web_contents()->SetDelegate(this); | |
| 193 | |
| 194 tab_contents_->web_contents()-> | |
| 195 GetMutableRendererPrefs()->browser_handles_top_level_requests = | |
| 196 handle_top_level_requests; | |
| 197 | |
| 198 if (!existing_contents) { | |
| 199 tab_contents_->web_contents()->GetRenderViewHost()->AllowBindings( | |
| 200 content::BINDINGS_POLICY_EXTERNAL_HOST); | |
| 201 } | |
| 202 | |
| 203 NavigationController* controller = | |
| 204 &tab_contents_->web_contents()->GetController(); | |
| 205 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
| 206 content::Source<NavigationController>(controller)); | |
| 207 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, | |
| 208 content::Source<NavigationController>(controller)); | |
| 209 registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CREATED_FOR_TAB, | |
| 210 content::Source<WebContents>(tab_contents_->web_contents())); | |
| 211 registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_DELETED, | |
| 212 content::NotificationService::AllSources()); | |
| 213 registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CREATED, | |
| 214 content::NotificationService::AllSources()); | |
| 215 | |
| 216 content::WebContentsObserver::Observe(tab_contents_->web_contents()); | |
| 217 | |
| 218 // Start loading initial URL | |
| 219 if (!initial_url.is_empty()) { | |
| 220 // Navigate out of context since we don't have a 'tab_handle_' yet. | |
| 221 MessageLoop::current()->PostTask( | |
| 222 FROM_HERE, | |
| 223 base::Bind(&ExternalTabContainer::Navigate, weak_factory_.GetWeakPtr(), | |
| 224 initial_url, referrer)); | |
| 225 } | |
| 226 | |
| 227 // We need WS_POPUP to be on the window during initialization, but | |
| 228 // once initialized we apply the requested style which may or may not | |
| 229 // include the popup bit. | |
| 230 // Note that it's important to do this before we call SetParent since | |
| 231 // during the SetParent call we will otherwise get a WA_ACTIVATE call | |
| 232 // that causes us to steal the current focus. | |
| 233 SetWindowLong(GWL_STYLE, (GetWindowLong(GWL_STYLE) & ~WS_POPUP) | style); | |
| 234 | |
| 235 // Now apply the parenting and style | |
| 236 if (parent) | |
| 237 SetParent(GetNativeView(), parent); | |
| 238 | |
| 239 ::ShowWindow(tab_contents_->web_contents()->GetNativeView(), SW_SHOWNA); | |
| 240 | |
| 241 LoadAccelerators(); | |
| 242 SetupExternalTabView(); | |
| 243 tab_contents_->blocked_content_tab_helper()->set_delegate(this); | |
| 244 return true; | |
| 245 } | |
| 246 | |
| 247 void ExternalTabContainer::Uninitialize() { | |
| 248 registrar_.RemoveAll(); | |
| 249 if (tab_contents_.get()) { | |
| 250 UnregisterRenderViewHost( | |
| 251 tab_contents_->web_contents()->GetRenderViewHost()); | |
| 252 | |
| 253 if (GetWidget()->GetRootView()) | |
| 254 GetWidget()->GetRootView()->RemoveAllChildViews(true); | |
| 255 | |
| 256 content::NotificationService::current()->Notify( | |
| 257 chrome::NOTIFICATION_EXTERNAL_TAB_CLOSED, | |
| 258 content::Source<NavigationController>( | |
| 259 &tab_contents_->web_contents()->GetController()), | |
| 260 content::Details<ExternalTabContainer>(this)); | |
| 261 | |
| 262 tab_contents_.reset(NULL); | |
| 263 } | |
| 264 | |
| 265 if (focus_manager_) { | |
| 266 focus_manager_->UnregisterAccelerators(this); | |
| 267 focus_manager_ = NULL; | |
| 268 } | |
| 269 | |
| 270 external_tab_view_ = NULL; | |
| 271 request_context_ = NULL; | |
| 272 tab_contents_container_ = NULL; | |
| 273 } | |
| 274 | |
| 275 bool ExternalTabContainer::Reinitialize( | |
| 276 AutomationProvider* automation_provider, | |
| 277 AutomationResourceMessageFilter* filter, | |
| 278 gfx::NativeWindow parent_window) { | |
| 279 if (!automation_provider || !filter) { | |
| 280 NOTREACHED(); | |
| 281 return false; | |
| 282 } | |
| 283 | |
| 284 automation_ = automation_provider; | |
| 285 automation_resource_message_filter_ = filter; | |
| 286 // Wait for the automation channel to be initialized before resuming pending | |
| 287 // render views and sending in the navigation state. | |
| 288 MessageLoop::current()->PostTask( | |
| 289 FROM_HERE, base::Bind(&ExternalTabContainer::OnReinitialize, | |
| 290 weak_factory_.GetWeakPtr())); | |
| 291 | |
| 292 if (parent_window) | |
| 293 SetParent(GetNativeView(), parent_window); | |
| 294 return true; | |
| 295 } | |
| 296 | |
| 297 void ExternalTabContainer::SetTabHandle(int handle) { | |
| 298 tab_handle_ = handle; | |
| 299 } | |
| 300 | |
| 301 void ExternalTabContainer::ProcessUnhandledAccelerator(const MSG& msg) { | |
| 302 NativeWebKeyboardEvent keyboard_event(msg); | |
| 303 unhandled_keyboard_event_handler_.HandleKeyboardEvent(keyboard_event, | |
| 304 focus_manager_); | |
| 305 } | |
| 306 | |
| 307 void ExternalTabContainer::FocusThroughTabTraversal( | |
| 308 bool reverse, bool restore_focus_to_view) { | |
| 309 DCHECK(tab_contents_.get()); | |
| 310 if (tab_contents_.get()) | |
| 311 tab_contents_->web_contents()->Focus(); | |
| 312 | |
| 313 // The tab_contents_ member can get destroyed in the context of the call to | |
| 314 // TabContentsViewViews::Focus() above. This method eventually calls SetFocus | |
| 315 // on the native window, which could end up dispatching messages like | |
| 316 // WM_DESTROY for the external tab. | |
| 317 if (tab_contents_.get() && restore_focus_to_view) | |
| 318 tab_contents_->web_contents()->FocusThroughTabTraversal(reverse); | |
| 319 } | |
| 320 | |
| 321 // static | |
| 322 bool ExternalTabContainer::IsExternalTabContainer(HWND window) { | |
| 323 return ViewProp::GetValue(window, kWindowObjectKey) != NULL; | |
| 324 } | |
| 325 | |
| 326 // static | |
| 327 ExternalTabContainer* ExternalTabContainer::GetContainerForTab( | |
| 328 HWND tab_window) { | |
| 329 HWND parent_window = ::GetParent(tab_window); | |
| 330 if (!::IsWindow(parent_window)) { | |
| 331 return NULL; | |
| 332 } | |
| 333 if (!IsExternalTabContainer(parent_window)) { | |
| 334 return NULL; | |
| 335 } | |
| 336 ExternalTabContainer* container = reinterpret_cast<ExternalTabContainer*>( | |
| 337 ViewProp::GetValue(parent_window, kWindowObjectKey)); | |
| 338 return container; | |
| 339 } | |
| 340 | |
| 341 // static | |
| 342 ExternalTabContainer* | |
| 343 ExternalTabContainer::GetExternalContainerFromNativeWindow( | |
| 344 gfx::NativeView native_window) { | |
| 345 ExternalTabContainer* tab_container = NULL; | |
| 346 if (native_window) { | |
| 347 tab_container = reinterpret_cast<ExternalTabContainer*>( | |
| 348 ViewProp::GetValue(native_window, kWindowObjectKey)); | |
| 349 } | |
| 350 return tab_container; | |
| 351 } | |
| 352 //////////////////////////////////////////////////////////////////////////////// | |
| 353 // ExternalTabContainer, content::WebContentsDelegate implementation: | |
| 354 | |
| 355 WebContents* ExternalTabContainer::OpenURLFromTab(WebContents* source, | |
| 356 const OpenURLParams& params) { | |
| 357 if (pending()) { | |
| 358 pending_open_url_requests_.push_back(params); | |
| 359 return NULL; | |
| 360 } | |
| 361 | |
| 362 switch (params.disposition) { | |
| 363 case CURRENT_TAB: | |
| 364 case SINGLETON_TAB: | |
| 365 case NEW_FOREGROUND_TAB: | |
| 366 case NEW_BACKGROUND_TAB: | |
| 367 case NEW_POPUP: | |
| 368 case NEW_WINDOW: | |
| 369 case SAVE_TO_DISK: | |
| 370 if (automation_) { | |
| 371 GURL referrer = GURL(WebSecurityPolicy::generateReferrerHeader( | |
| 372 params.referrer.policy, | |
| 373 params.url, | |
| 374 WebString::fromUTF8(params.referrer.url.spec())).utf8()); | |
| 375 automation_->Send(new AutomationMsg_OpenURL(tab_handle_, | |
| 376 params.url, | |
| 377 referrer, | |
| 378 params.disposition)); | |
| 379 // TODO(ananta) | |
| 380 // We should populate other fields in the | |
| 381 // ViewHostMsg_FrameNavigate_Params structure. Another option could be | |
| 382 // to refactor the UpdateHistoryForNavigation function in TabContents. | |
| 383 content::FrameNavigateParams nav_params; | |
| 384 nav_params.referrer = content::Referrer(referrer, | |
| 385 params.referrer.policy); | |
| 386 nav_params.url = params.url; | |
| 387 nav_params.page_id = -1; | |
| 388 nav_params.transition = content::PAGE_TRANSITION_LINK; | |
| 389 | |
| 390 content::LoadCommittedDetails details; | |
| 391 details.did_replace_entry = false; | |
| 392 | |
| 393 scoped_refptr<history::HistoryAddPageArgs> add_page_args( | |
| 394 tab_contents_->history_tab_helper()-> | |
| 395 CreateHistoryAddPageArgs(params.url, details, nav_params)); | |
| 396 tab_contents_->history_tab_helper()-> | |
| 397 UpdateHistoryForNavigation(add_page_args); | |
| 398 | |
| 399 return tab_contents_->web_contents(); | |
| 400 } | |
| 401 break; | |
| 402 default: | |
| 403 NOTREACHED(); | |
| 404 break; | |
| 405 } | |
| 406 | |
| 407 return NULL; | |
| 408 } | |
| 409 | |
| 410 void ExternalTabContainer::NavigationStateChanged(const WebContents* source, | |
| 411 unsigned changed_flags) { | |
| 412 if (automation_) { | |
| 413 NavigationInfo nav_info; | |
| 414 if (InitNavigationInfo(&nav_info, content::NAVIGATION_TYPE_NAV_IGNORE, 0)) | |
| 415 automation_->Send(new AutomationMsg_NavigationStateChanged( | |
| 416 tab_handle_, changed_flags, nav_info)); | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 void ExternalTabContainer::AddNewContents(WebContents* source, | |
| 421 WebContents* new_contents, | |
| 422 WindowOpenDisposition disposition, | |
| 423 const gfx::Rect& initial_pos, | |
| 424 bool user_gesture) { | |
| 425 if (!automation_) { | |
| 426 DCHECK(pending_); | |
| 427 LOG(ERROR) << "Invalid automation provider. Dropping new contents notify"; | |
| 428 delete new_contents; | |
| 429 return; | |
| 430 } | |
| 431 | |
| 432 scoped_refptr<ExternalTabContainer> new_container; | |
| 433 // If the host is a browser like IE8, then the URL being navigated to in the | |
| 434 // new tab contents could potentially navigate back to Chrome from a new | |
| 435 // IE process. We support full tab mode only for IE and hence we use that as | |
| 436 // a determining factor in whether the new ExternalTabContainer instance is | |
| 437 // created as pending or not. | |
| 438 if (!route_all_top_level_navigations_) { | |
| 439 new_container = new ExternalTabContainer(NULL, NULL); | |
| 440 } else { | |
| 441 // Reuse the same tab handle here as the new container instance is a dummy | |
| 442 // instance which does not have an automation client connected at the other | |
| 443 // end. | |
| 444 new_container = new TemporaryPopupExternalTabContainer( | |
| 445 automation_, automation_resource_message_filter_.get()); | |
| 446 new_container->SetTabHandle(tab_handle_); | |
| 447 } | |
| 448 | |
| 449 // Make sure that ExternalTabContainer instance is initialized with | |
| 450 // an unwrapped Profile. | |
| 451 scoped_ptr<TabContentsWrapper> wrapper(new TabContentsWrapper(new_contents)); | |
| 452 bool result = new_container->Init( | |
| 453 wrapper->profile()->GetOriginalProfile(), | |
| 454 NULL, | |
| 455 initial_pos, | |
| 456 WS_CHILD, | |
| 457 load_requests_via_automation_, | |
| 458 handle_top_level_requests_, | |
| 459 wrapper.get(), | |
| 460 GURL(), | |
| 461 GURL(), | |
| 462 true, | |
| 463 route_all_top_level_navigations_); | |
| 464 | |
| 465 if (result) { | |
| 466 Profile* profile = wrapper->profile(); | |
| 467 wrapper.release(); // Ownership has been transferred. | |
| 468 if (route_all_top_level_navigations_) { | |
| 469 return; | |
| 470 } | |
| 471 uintptr_t cookie = reinterpret_cast<uintptr_t>(new_container.get()); | |
| 472 pending_tabs_.Get()[cookie] = new_container; | |
| 473 new_container->set_pending(true); | |
| 474 new_container->set_is_popup_window(disposition == NEW_POPUP); | |
| 475 AttachExternalTabParams attach_params_; | |
| 476 attach_params_.cookie = static_cast<uint64>(cookie); | |
| 477 attach_params_.dimensions = initial_pos; | |
| 478 attach_params_.user_gesture = user_gesture; | |
| 479 attach_params_.disposition = disposition; | |
| 480 attach_params_.profile_name = WideToUTF8( | |
| 481 profile->GetPath().DirName().BaseName().value()); | |
| 482 automation_->Send(new AutomationMsg_AttachExternalTab( | |
| 483 tab_handle_, attach_params_)); | |
| 484 } else { | |
| 485 NOTREACHED(); | |
| 486 } | |
| 487 } | |
| 488 | |
| 489 void ExternalTabContainer::WebContentsCreated(WebContents* source_contents, | |
| 490 int64 source_frame_id, | |
| 491 const GURL& target_url, | |
| 492 WebContents* new_contents) { | |
| 493 RenderViewHost* rvh = new_contents->GetRenderViewHost(); | |
| 494 DCHECK(rvh != NULL); | |
| 495 | |
| 496 // Register this render view as a pending render view, i.e. any network | |
| 497 // requests initiated by this render view would be serviced when the | |
| 498 // external host connects to the new external tab instance. | |
| 499 RegisterRenderViewHostForAutomation(rvh, true); | |
| 500 } | |
| 501 | |
| 502 void ExternalTabContainer::CloseContents(content::WebContents* source) { | |
| 503 if (!automation_) | |
| 504 return; | |
| 505 | |
| 506 if (unload_reply_message_) { | |
| 507 AutomationMsg_RunUnloadHandlers::WriteReplyParams(unload_reply_message_, | |
| 508 true); | |
| 509 automation_->Send(unload_reply_message_); | |
| 510 unload_reply_message_ = NULL; | |
| 511 } else { | |
| 512 automation_->Send(new AutomationMsg_CloseExternalTab(tab_handle_)); | |
| 513 } | |
| 514 } | |
| 515 | |
| 516 void ExternalTabContainer::MoveContents(WebContents* source, | |
| 517 const gfx::Rect& pos) { | |
| 518 if (automation_ && is_popup_window_) | |
| 519 automation_->Send(new AutomationMsg_MoveWindow(tab_handle_, pos)); | |
| 520 } | |
| 521 | |
| 522 TabContentsWrapper* ExternalTabContainer::GetConstrainingContentsWrapper( | |
| 523 TabContentsWrapper* source) { | |
| 524 return source; | |
| 525 } | |
| 526 | |
| 527 bool ExternalTabContainer::IsPopupOrPanel(const WebContents* source) const { | |
| 528 return is_popup_window_; | |
| 529 } | |
| 530 | |
| 531 void ExternalTabContainer::UpdateTargetURL(WebContents* source, | |
| 532 int32 page_id, | |
| 533 const GURL& url) { | |
| 534 Browser::UpdateTargetURLHelper(source, page_id, url); | |
| 535 if (automation_) { | |
| 536 std::wstring url_string = CA2W(url.spec().c_str()); | |
| 537 automation_->Send( | |
| 538 new AutomationMsg_UpdateTargetUrl(tab_handle_, url_string)); | |
| 539 } | |
| 540 } | |
| 541 | |
| 542 void ExternalTabContainer::ContentsZoomChange(bool zoom_in) { | |
| 543 } | |
| 544 | |
| 545 gfx::NativeWindow ExternalTabContainer::GetFrameNativeWindow() { | |
| 546 return hwnd(); | |
| 547 } | |
| 548 | |
| 549 bool ExternalTabContainer::TakeFocus(bool reverse) { | |
| 550 if (automation_) { | |
| 551 automation_->Send(new AutomationMsg_TabbedOut(tab_handle_, | |
| 552 base::win::IsShiftPressed())); | |
| 553 } | |
| 554 | |
| 555 return true; | |
| 556 } | |
| 557 | |
| 558 bool ExternalTabContainer::CanDownload(RenderViewHost* render_view_host, | |
| 559 int request_id, | |
| 560 const std::string& request_method) { | |
| 561 if (load_requests_via_automation_) { | |
| 562 if (automation_) { | |
| 563 // In case the host needs to show UI that needs to take the focus. | |
| 564 ::AllowSetForegroundWindow(ASFW_ANY); | |
| 565 | |
| 566 BrowserThread::PostTask( | |
| 567 BrowserThread::IO, FROM_HERE, | |
| 568 base::Bind( | |
| 569 base::IgnoreResult( | |
| 570 &AutomationResourceMessageFilter::SendDownloadRequestToHost), | |
| 571 automation_resource_message_filter_.get(), 0, tab_handle_, | |
| 572 request_id)); | |
| 573 } | |
| 574 } else { | |
| 575 DLOG(WARNING) << "Downloads are only supported with host browser network " | |
| 576 "stack enabled."; | |
| 577 } | |
| 578 | |
| 579 // Never allow downloads. | |
| 580 return false; | |
| 581 } | |
| 582 | |
| 583 void ExternalTabContainer::RegisterRenderViewHostForAutomation( | |
| 584 RenderViewHost* render_view_host, bool pending_view) { | |
| 585 if (render_view_host) { | |
| 586 AutomationResourceMessageFilter::RegisterRenderView( | |
| 587 render_view_host->GetProcess()->GetID(), | |
| 588 render_view_host->GetRoutingID(), | |
| 589 tab_handle(), | |
| 590 automation_resource_message_filter_, | |
| 591 pending_view); | |
| 592 } | |
| 593 } | |
| 594 | |
| 595 void ExternalTabContainer::RegisterRenderViewHost( | |
| 596 RenderViewHost* render_view_host) { | |
| 597 // RenderViewHost instances that are to be associated with this | |
| 598 // ExternalTabContainer should share the same resource request automation | |
| 599 // settings. | |
| 600 RegisterRenderViewHostForAutomation( | |
| 601 render_view_host, | |
| 602 false); // Network requests should not be handled later. | |
| 603 } | |
| 604 | |
| 605 void ExternalTabContainer::UnregisterRenderViewHost( | |
| 606 RenderViewHost* render_view_host) { | |
| 607 // Undo the resource automation registration performed in | |
| 608 // ExternalTabContainer::RegisterRenderViewHost. | |
| 609 if (render_view_host) { | |
| 610 AutomationResourceMessageFilter::UnRegisterRenderView( | |
| 611 render_view_host->GetProcess()->GetID(), | |
| 612 render_view_host->GetRoutingID()); | |
| 613 } | |
| 614 } | |
| 615 | |
| 616 content::JavaScriptDialogCreator* | |
| 617 ExternalTabContainer::GetJavaScriptDialogCreator() { | |
| 618 return GetJavaScriptDialogCreatorInstance(); | |
| 619 } | |
| 620 | |
| 621 bool ExternalTabContainer::HandleContextMenu( | |
| 622 const content::ContextMenuParams& params) { | |
| 623 if (!automation_) { | |
| 624 NOTREACHED(); | |
| 625 return false; | |
| 626 } | |
| 627 external_context_menu_.reset( | |
| 628 new RenderViewContextMenuViews(web_contents(), params)); | |
| 629 external_context_menu_->SetExternal(); | |
| 630 external_context_menu_->Init(); | |
| 631 external_context_menu_->UpdateMenuItemStates(); | |
| 632 | |
| 633 scoped_ptr<ContextMenuModel> context_menu_model( | |
| 634 ConvertMenuModel(&external_context_menu_->menu_model())); | |
| 635 | |
| 636 POINT screen_pt = { params.x, params.y }; | |
| 637 MapWindowPoints(GetNativeView(), HWND_DESKTOP, &screen_pt, 1); | |
| 638 | |
| 639 MiniContextMenuParams ipc_params; | |
| 640 ipc_params.screen_x = screen_pt.x; | |
| 641 ipc_params.screen_y = screen_pt.y; | |
| 642 ipc_params.link_url = params.link_url; | |
| 643 ipc_params.unfiltered_link_url = params.unfiltered_link_url; | |
| 644 ipc_params.src_url = params.src_url; | |
| 645 ipc_params.page_url = params.page_url; | |
| 646 ipc_params.keyword_url = params.keyword_url; | |
| 647 ipc_params.frame_url = params.frame_url; | |
| 648 | |
| 649 bool rtl = base::i18n::IsRTL(); | |
| 650 automation_->Send( | |
| 651 new AutomationMsg_ForwardContextMenuToExternalHost(tab_handle_, | |
| 652 *context_menu_model, | |
| 653 rtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN, ipc_params)); | |
| 654 | |
| 655 return true; | |
| 656 } | |
| 657 | |
| 658 bool ExternalTabContainer::ExecuteContextMenuCommand(int command) { | |
| 659 if (!external_context_menu_.get()) { | |
| 660 NOTREACHED(); | |
| 661 return false; | |
| 662 } | |
| 663 | |
| 664 switch (command) { | |
| 665 case IDS_CONTENT_CONTEXT_SAVEAUDIOAS: | |
| 666 case IDS_CONTENT_CONTEXT_SAVEVIDEOAS: | |
| 667 case IDS_CONTENT_CONTEXT_SAVEIMAGEAS: | |
| 668 case IDS_CONTENT_CONTEXT_SAVELINKAS: { | |
| 669 NOTREACHED(); // Should be handled in host. | |
| 670 break; | |
| 671 } | |
| 672 } | |
| 673 | |
| 674 external_context_menu_->ExecuteCommand(command); | |
| 675 return true; | |
| 676 } | |
| 677 | |
| 678 bool ExternalTabContainer::PreHandleKeyboardEvent( | |
| 679 const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) { | |
| 680 return false; | |
| 681 } | |
| 682 | |
| 683 void ExternalTabContainer::HandleKeyboardEvent( | |
| 684 const NativeWebKeyboardEvent& event) { | |
| 685 ProcessUnhandledKeyStroke(event.os_event.hwnd, event.os_event.message, | |
| 686 event.os_event.wParam, event.os_event.lParam); | |
| 687 } | |
| 688 | |
| 689 void ExternalTabContainer::BeforeUnloadFired(WebContents* tab, | |
| 690 bool proceed, | |
| 691 bool* proceed_to_fire_unload) { | |
| 692 *proceed_to_fire_unload = true; | |
| 693 | |
| 694 if (!automation_) { | |
| 695 delete unload_reply_message_; | |
| 696 unload_reply_message_ = NULL; | |
| 697 return; | |
| 698 } | |
| 699 | |
| 700 if (!unload_reply_message_) { | |
| 701 NOTREACHED() << "**** NULL unload reply message pointer."; | |
| 702 return; | |
| 703 } | |
| 704 | |
| 705 if (!proceed) { | |
| 706 AutomationMsg_RunUnloadHandlers::WriteReplyParams(unload_reply_message_, | |
| 707 false); | |
| 708 automation_->Send(unload_reply_message_); | |
| 709 unload_reply_message_ = NULL; | |
| 710 *proceed_to_fire_unload = false; | |
| 711 } | |
| 712 } | |
| 713 | |
| 714 void ExternalTabContainer::ShowRepostFormWarningDialog( | |
| 715 WebContents* source) { | |
| 716 browser::ShowTabModalConfirmDialog( | |
| 717 new RepostFormWarningController(source), | |
| 718 TabContentsWrapper::GetCurrentWrapperForContents(source)); | |
| 719 } | |
| 720 | |
| 721 void ExternalTabContainer::RunFileChooser( | |
| 722 WebContents* tab, const content::FileChooserParams& params) { | |
| 723 Browser::RunFileChooserHelper(tab, params); | |
| 724 } | |
| 725 | |
| 726 void ExternalTabContainer::EnumerateDirectory(WebContents* tab, int request_id, | |
| 727 const FilePath& path) { | |
| 728 Browser::EnumerateDirectoryHelper(tab, request_id, path); | |
| 729 } | |
| 730 | |
| 731 void ExternalTabContainer::JSOutOfMemory(WebContents* tab) { | |
| 732 Browser::JSOutOfMemoryHelper(tab); | |
| 733 } | |
| 734 | |
| 735 void ExternalTabContainer::RegisterProtocolHandler(WebContents* tab, | |
| 736 const std::string& protocol, | |
| 737 const GURL& url, | |
| 738 const string16& title) { | |
| 739 Browser::RegisterProtocolHandlerHelper(tab, protocol, url, title); | |
| 740 } | |
| 741 | |
| 742 void ExternalTabContainer::RegisterIntentHandler(WebContents* tab, | |
| 743 const string16& action, | |
| 744 const string16& type, | |
| 745 const string16& href, | |
| 746 const string16& title, | |
| 747 const string16& disposition) { | |
| 748 Browser::RegisterIntentHandlerHelper( | |
| 749 tab, action, type, href, title, disposition); | |
| 750 } | |
| 751 | |
| 752 void ExternalTabContainer::WebIntentDispatch( | |
| 753 WebContents* tab, | |
| 754 content::WebIntentsDispatcher* intents_dispatcher) { | |
| 755 // TODO(binji) How do we want to display the WebIntentPicker bubble if there | |
| 756 // is no BrowserWindow? | |
| 757 delete intents_dispatcher; | |
| 758 } | |
| 759 | |
| 760 void ExternalTabContainer::FindReply(WebContents* tab, | |
| 761 int request_id, | |
| 762 int number_of_matches, | |
| 763 const gfx::Rect& selection_rect, | |
| 764 int active_match_ordinal, | |
| 765 bool final_update) { | |
| 766 Browser::FindReplyHelper(tab, request_id, number_of_matches, selection_rect, | |
| 767 active_match_ordinal, final_update); | |
| 768 } | |
| 769 | |
| 770 void ExternalTabContainer::CrashedPlugin(WebContents* tab, | |
| 771 const FilePath& plugin_path) { | |
| 772 Browser::CrashedPluginHelper(tab, plugin_path); | |
| 773 } | |
| 774 | |
| 775 bool ExternalTabContainer::OnMessageReceived(const IPC::Message& message) { | |
| 776 bool handled = true; | |
| 777 IPC_BEGIN_MESSAGE_MAP(ExternalTabContainer, message) | |
| 778 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ForwardMessageToExternalHost, | |
| 779 OnForwardMessageToExternalHost) | |
| 780 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 781 IPC_END_MESSAGE_MAP() | |
| 782 return handled; | |
| 783 } | |
| 784 | |
| 785 void ExternalTabContainer::DidFailProvisionalLoad( | |
| 786 int64 frame_id, | |
| 787 bool is_main_frame, | |
| 788 const GURL& validated_url, | |
| 789 int error_code, | |
| 790 const string16& error_description) { | |
| 791 automation_->Send(new AutomationMsg_NavigationFailed( | |
| 792 tab_handle_, error_code, validated_url)); | |
| 793 ignore_next_load_notification_ = true; | |
| 794 } | |
| 795 | |
| 796 void ExternalTabContainer::OnForwardMessageToExternalHost( | |
| 797 const std::string& message, | |
| 798 const std::string& origin, | |
| 799 const std::string& target) { | |
| 800 if (automation_) { | |
| 801 automation_->Send(new AutomationMsg_ForwardMessageToExternalHost( | |
| 802 tab_handle_, message, origin, target)); | |
| 803 } | |
| 804 } | |
| 805 | |
| 806 //////////////////////////////////////////////////////////////////////////////// | |
| 807 // ExternalTabContainer, NotificationObserver implementation: | |
| 808 | |
| 809 void ExternalTabContainer::Observe( | |
| 810 int type, | |
| 811 const content::NotificationSource& source, | |
| 812 const content::NotificationDetails& details) { | |
| 813 if (!automation_) | |
| 814 return; | |
| 815 | |
| 816 static const int kHttpClientErrorStart = 400; | |
| 817 static const int kHttpServerErrorEnd = 510; | |
| 818 | |
| 819 switch (type) { | |
| 820 case content::NOTIFICATION_LOAD_STOP: { | |
| 821 const LoadNotificationDetails* load = | |
| 822 content::Details<LoadNotificationDetails>(details).ptr(); | |
| 823 if (load && content::PageTransitionIsMainFrame(load->origin)) { | |
| 824 TRACE_EVENT_END_ETW("ExternalTabContainer::Navigate", 0, | |
| 825 load->url.spec()); | |
| 826 automation_->Send(new AutomationMsg_TabLoaded(tab_handle_, | |
| 827 load->url)); | |
| 828 } | |
| 829 break; | |
| 830 } | |
| 831 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { | |
| 832 if (ignore_next_load_notification_) { | |
| 833 ignore_next_load_notification_ = false; | |
| 834 return; | |
| 835 } | |
| 836 | |
| 837 const content::LoadCommittedDetails* commit = | |
| 838 content::Details<content::LoadCommittedDetails>(details).ptr(); | |
| 839 | |
| 840 if (commit->http_status_code >= kHttpClientErrorStart && | |
| 841 commit->http_status_code <= kHttpServerErrorEnd) { | |
| 842 automation_->Send(new AutomationMsg_NavigationFailed( | |
| 843 tab_handle_, commit->http_status_code, commit->entry->GetURL())); | |
| 844 | |
| 845 ignore_next_load_notification_ = true; | |
| 846 } else { | |
| 847 NavigationInfo navigation_info; | |
| 848 // When the previous entry index is invalid, it will be -1, which | |
| 849 // will still make the computation come out right (navigating to the | |
| 850 // 0th entry will be +1). | |
| 851 if (InitNavigationInfo(&navigation_info, commit->type, | |
| 852 commit->previous_entry_index - | |
| 853 tab_contents_->web_contents()-> | |
| 854 GetController().GetLastCommittedEntryIndex())) | |
| 855 automation_->Send(new AutomationMsg_DidNavigate(tab_handle_, | |
| 856 navigation_info)); | |
| 857 } | |
| 858 break; | |
| 859 } | |
| 860 case content::NOTIFICATION_RENDER_VIEW_HOST_CREATED_FOR_TAB: { | |
| 861 if (load_requests_via_automation_) { | |
| 862 RenderViewHost* rvh = content::Details<RenderViewHost>(details).ptr(); | |
| 863 RegisterRenderViewHostForAutomation(rvh, false); | |
| 864 } | |
| 865 break; | |
| 866 } | |
| 867 case content::NOTIFICATION_RENDER_VIEW_HOST_DELETED: { | |
| 868 if (load_requests_via_automation_) { | |
| 869 RenderViewHost* rvh = content::Source<RenderViewHost>(source).ptr(); | |
| 870 UnregisterRenderViewHost(rvh); | |
| 871 } | |
| 872 break; | |
| 873 } | |
| 874 case content::NOTIFICATION_RENDER_VIEW_HOST_CREATED: { | |
| 875 if (load_requests_via_automation_) { | |
| 876 RenderViewHost* rvh = content::Source<RenderViewHost>(source).ptr(); | |
| 877 RegisterRenderViewHostForAutomation(rvh, false); | |
| 878 } | |
| 879 break; | |
| 880 } | |
| 881 default: | |
| 882 NOTREACHED(); | |
| 883 } | |
| 884 } | |
| 885 | |
| 886 //////////////////////////////////////////////////////////////////////////////// | |
| 887 // ExternalTabContainer, views::NativeWidgetWin overrides: | |
| 888 | |
| 889 LRESULT ExternalTabContainer::OnCreate(LPCREATESTRUCT create_struct) { | |
| 890 LRESULT result = views::NativeWidgetWin::OnCreate(create_struct); | |
| 891 if (result == 0) { | |
| 892 // Grab a reference here which will be released in OnFinalMessage | |
| 893 AddRef(); | |
| 894 } | |
| 895 return result; | |
| 896 } | |
| 897 | |
| 898 void ExternalTabContainer::OnDestroy() { | |
| 899 prop_.reset(); | |
| 900 Uninitialize(); | |
| 901 NativeWidgetWin::OnDestroy(); | |
| 902 } | |
| 903 | |
| 904 void ExternalTabContainer::OnFinalMessage(HWND window) { | |
| 905 GetWidget()->OnNativeWidgetDestroyed(); | |
| 906 // Release the reference which we grabbed in WM_CREATE. | |
| 907 Release(); | |
| 908 } | |
| 909 | |
| 910 void ExternalTabContainer::RunUnloadHandlers(IPC::Message* reply_message) { | |
| 911 if (!automation_) { | |
| 912 delete reply_message; | |
| 913 return; | |
| 914 } | |
| 915 | |
| 916 // If we have a pending unload message, then just respond back to this | |
| 917 // request and continue processing the previous unload message. | |
| 918 if (unload_reply_message_) { | |
| 919 AutomationMsg_RunUnloadHandlers::WriteReplyParams(reply_message, true); | |
| 920 automation_->Send(reply_message); | |
| 921 return; | |
| 922 } | |
| 923 | |
| 924 unload_reply_message_ = reply_message; | |
| 925 bool wait_for_unload_handlers = | |
| 926 tab_contents_.get() && | |
| 927 Browser::RunUnloadEventsHelper(tab_contents_->web_contents()); | |
| 928 if (!wait_for_unload_handlers) { | |
| 929 AutomationMsg_RunUnloadHandlers::WriteReplyParams(reply_message, true); | |
| 930 automation_->Send(reply_message); | |
| 931 unload_reply_message_ = NULL; | |
| 932 } | |
| 933 } | |
| 934 | |
| 935 //////////////////////////////////////////////////////////////////////////////// | |
| 936 // ExternalTabContainer, private: | |
| 937 bool ExternalTabContainer::ProcessUnhandledKeyStroke(HWND window, | |
| 938 UINT message, | |
| 939 WPARAM wparam, | |
| 940 LPARAM lparam) { | |
| 941 if (!automation_) { | |
| 942 return false; | |
| 943 } | |
| 944 if ((wparam == VK_TAB) && !base::win::IsCtrlPressed()) { | |
| 945 // Tabs are handled separately (except if this is Ctrl-Tab or | |
| 946 // Ctrl-Shift-Tab) | |
| 947 return false; | |
| 948 } | |
| 949 | |
| 950 // Send this keystroke to the external host as it could be processed as an | |
| 951 // accelerator there. If the host does not handle this accelerator, it will | |
| 952 // reflect the accelerator back to us via the ProcessUnhandledAccelerator | |
| 953 // method. | |
| 954 MSG msg = {0}; | |
| 955 msg.hwnd = window; | |
| 956 msg.message = message; | |
| 957 msg.wParam = wparam; | |
| 958 msg.lParam = lparam; | |
| 959 automation_->Send(new AutomationMsg_HandleAccelerator(tab_handle_, msg)); | |
| 960 return true; | |
| 961 } | |
| 962 | |
| 963 bool ExternalTabContainer::InitNavigationInfo(NavigationInfo* nav_info, | |
| 964 content::NavigationType nav_type, | |
| 965 int relative_offset) { | |
| 966 DCHECK(nav_info); | |
| 967 NavigationEntry* entry = | |
| 968 tab_contents_->web_contents()->GetController().GetActiveEntry(); | |
| 969 // If this is very early in the game then we may not have an entry. | |
| 970 if (!entry) | |
| 971 return false; | |
| 972 | |
| 973 nav_info->navigation_type = nav_type; | |
| 974 nav_info->relative_offset = relative_offset; | |
| 975 nav_info->navigation_index = | |
| 976 tab_contents_->web_contents()->GetController().GetCurrentEntryIndex(); | |
| 977 nav_info->url = entry->GetURL(); | |
| 978 nav_info->referrer = entry->GetReferrer().url; | |
| 979 nav_info->title = UTF16ToWideHack(entry->GetTitle()); | |
| 980 if (nav_info->title.empty()) | |
| 981 nav_info->title = UTF8ToWide(nav_info->url.spec()); | |
| 982 | |
| 983 nav_info->security_style = entry->GetSSL().security_style; | |
| 984 int content_status = entry->GetSSL().content_status; | |
| 985 nav_info->displayed_insecure_content = | |
| 986 !!(content_status & SSLStatus::DISPLAYED_INSECURE_CONTENT); | |
| 987 nav_info->ran_insecure_content = | |
| 988 !!(content_status & SSLStatus::RAN_INSECURE_CONTENT); | |
| 989 return true; | |
| 990 } | |
| 991 | |
| 992 scoped_refptr<ExternalTabContainer> ExternalTabContainer::RemovePendingTab( | |
| 993 uintptr_t cookie) { | |
| 994 ExternalTabContainer::PendingTabs& pending_tabs = pending_tabs_.Get(); | |
| 995 PendingTabs::iterator index = pending_tabs.find(cookie); | |
| 996 if (index != pending_tabs.end()) { | |
| 997 scoped_refptr<ExternalTabContainer> container = (*index).second; | |
| 998 pending_tabs.erase(index); | |
| 999 return container; | |
| 1000 } | |
| 1001 | |
| 1002 NOTREACHED() << "Failed to find ExternalTabContainer for cookie: " | |
| 1003 << cookie; | |
| 1004 return NULL; | |
| 1005 } | |
| 1006 | |
| 1007 SkColor ExternalTabContainer::GetInfoBarSeparatorColor() const { | |
| 1008 return ThemeService::GetDefaultColor(ThemeService::COLOR_TOOLBAR_SEPARATOR); | |
| 1009 } | |
| 1010 | |
| 1011 void ExternalTabContainer::InfoBarContainerStateChanged(bool is_animating) { | |
| 1012 if (external_tab_view_) | |
| 1013 external_tab_view_->Layout(); | |
| 1014 } | |
| 1015 | |
| 1016 bool ExternalTabContainer::DrawInfoBarArrows(int* x) const { | |
| 1017 return false; | |
| 1018 } | |
| 1019 | |
| 1020 bool ExternalTabContainer::AcceleratorPressed( | |
| 1021 const ui::Accelerator& accelerator) { | |
| 1022 std::map<ui::Accelerator, int>::const_iterator iter = | |
| 1023 accelerator_table_.find(accelerator); | |
| 1024 DCHECK(iter != accelerator_table_.end()); | |
| 1025 | |
| 1026 if (!tab_contents_.get() || | |
| 1027 !tab_contents_->web_contents()->GetRenderViewHost()) { | |
| 1028 NOTREACHED(); | |
| 1029 return false; | |
| 1030 } | |
| 1031 | |
| 1032 RenderViewHost* host = tab_contents_->web_contents()->GetRenderViewHost(); | |
| 1033 int command_id = iter->second; | |
| 1034 switch (command_id) { | |
| 1035 case IDC_ZOOM_PLUS: | |
| 1036 host->Zoom(content::PAGE_ZOOM_IN); | |
| 1037 break; | |
| 1038 case IDC_ZOOM_NORMAL: | |
| 1039 host->Zoom(content::PAGE_ZOOM_RESET); | |
| 1040 break; | |
| 1041 case IDC_ZOOM_MINUS: | |
| 1042 host->Zoom(content::PAGE_ZOOM_OUT); | |
| 1043 break; | |
| 1044 case IDC_DEV_TOOLS: | |
| 1045 DevToolsWindow::ToggleDevToolsWindow( | |
| 1046 tab_contents_->web_contents()->GetRenderViewHost(), | |
| 1047 DEVTOOLS_TOGGLE_ACTION_NONE); | |
| 1048 break; | |
| 1049 case IDC_DEV_TOOLS_CONSOLE: | |
| 1050 DevToolsWindow::ToggleDevToolsWindow( | |
| 1051 tab_contents_->web_contents()->GetRenderViewHost(), | |
| 1052 DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE); | |
| 1053 break; | |
| 1054 case IDC_DEV_TOOLS_INSPECT: | |
| 1055 DevToolsWindow::ToggleDevToolsWindow( | |
| 1056 tab_contents_->web_contents()->GetRenderViewHost(), | |
| 1057 DEVTOOLS_TOGGLE_ACTION_INSPECT); | |
| 1058 break; | |
| 1059 default: | |
| 1060 NOTREACHED() << "Unsupported accelerator: " << command_id; | |
| 1061 return false; | |
| 1062 } | |
| 1063 return true; | |
| 1064 } | |
| 1065 | |
| 1066 bool ExternalTabContainer::CanHandleAccelerators() const { | |
| 1067 return true; | |
| 1068 } | |
| 1069 | |
| 1070 void ExternalTabContainer::Navigate(const GURL& url, const GURL& referrer) { | |
| 1071 if (!tab_contents_.get()) { | |
| 1072 NOTREACHED(); | |
| 1073 return; | |
| 1074 } | |
| 1075 | |
| 1076 TRACE_EVENT_BEGIN_ETW("ExternalTabContainer::Navigate", 0, url.spec()); | |
| 1077 | |
| 1078 tab_contents_->web_contents()->GetController().LoadURL( | |
| 1079 url, content::Referrer(referrer, WebKit::WebReferrerPolicyDefault), | |
| 1080 content::PAGE_TRANSITION_START_PAGE, std::string()); | |
| 1081 } | |
| 1082 | |
| 1083 bool ExternalTabContainer::OnGoToEntryOffset(int offset) { | |
| 1084 if (load_requests_via_automation_) { | |
| 1085 automation_->Send(new AutomationMsg_RequestGoToHistoryEntryOffset( | |
| 1086 tab_handle_, offset)); | |
| 1087 return false; | |
| 1088 } | |
| 1089 | |
| 1090 return true; | |
| 1091 } | |
| 1092 | |
| 1093 void ExternalTabContainer::LoadAccelerators() { | |
| 1094 HACCEL accelerator_table = AtlLoadAccelerators(IDR_CHROMEFRAME); | |
| 1095 DCHECK(accelerator_table); | |
| 1096 | |
| 1097 // We have to copy the table to access its contents. | |
| 1098 int count = CopyAcceleratorTable(accelerator_table, 0, 0); | |
| 1099 if (count == 0) { | |
| 1100 // Nothing to do in that case. | |
| 1101 return; | |
| 1102 } | |
| 1103 | |
| 1104 scoped_array<ACCEL> scoped_accelerators(new ACCEL[count]); | |
| 1105 ACCEL* accelerators = scoped_accelerators.get(); | |
| 1106 DCHECK(accelerators != NULL); | |
| 1107 | |
| 1108 CopyAcceleratorTable(accelerator_table, accelerators, count); | |
| 1109 | |
| 1110 focus_manager_ = GetWidget()->GetFocusManager(); | |
| 1111 DCHECK(focus_manager_); | |
| 1112 | |
| 1113 // Let's fill our own accelerator table. | |
| 1114 for (int i = 0; i < count; ++i) { | |
| 1115 bool alt_down = (accelerators[i].fVirt & FALT) == FALT; | |
| 1116 bool ctrl_down = (accelerators[i].fVirt & FCONTROL) == FCONTROL; | |
| 1117 bool shift_down = (accelerators[i].fVirt & FSHIFT) == FSHIFT; | |
| 1118 ui::Accelerator accelerator( | |
| 1119 static_cast<ui::KeyboardCode>(accelerators[i].key), | |
| 1120 shift_down, ctrl_down, alt_down); | |
| 1121 accelerator_table_[accelerator] = accelerators[i].cmd; | |
| 1122 | |
| 1123 // Also register with the focus manager. | |
| 1124 if (focus_manager_) { | |
| 1125 focus_manager_->RegisterAccelerator( | |
| 1126 accelerator, ui::AcceleratorManager::kNormalPriority, this); | |
| 1127 } | |
| 1128 } | |
| 1129 } | |
| 1130 | |
| 1131 void ExternalTabContainer::OnReinitialize() { | |
| 1132 if (load_requests_via_automation_) { | |
| 1133 RenderViewHost* rvh = tab_contents_->web_contents()->GetRenderViewHost(); | |
| 1134 if (rvh) { | |
| 1135 AutomationResourceMessageFilter::ResumePendingRenderView( | |
| 1136 rvh->GetProcess()->GetID(), rvh->GetRoutingID(), | |
| 1137 tab_handle_, automation_resource_message_filter_); | |
| 1138 } | |
| 1139 } | |
| 1140 | |
| 1141 NavigationStateChanged(web_contents(), 0); | |
| 1142 ServicePendingOpenURLRequests(); | |
| 1143 } | |
| 1144 | |
| 1145 void ExternalTabContainer::ServicePendingOpenURLRequests() { | |
| 1146 DCHECK(pending()); | |
| 1147 | |
| 1148 set_pending(false); | |
| 1149 | |
| 1150 for (size_t index = 0; index < pending_open_url_requests_.size(); | |
| 1151 ++index) { | |
| 1152 const OpenURLParams& url_request = pending_open_url_requests_[index]; | |
| 1153 OpenURLFromTab(web_contents(), url_request); | |
| 1154 } | |
| 1155 pending_open_url_requests_.clear(); | |
| 1156 } | |
| 1157 | |
| 1158 void ExternalTabContainer::SetupExternalTabView() { | |
| 1159 // Create a TabContentsContainer to handle focus cycling using Tab and | |
| 1160 // Shift-Tab. | |
| 1161 tab_contents_container_ = new TabContentsContainer; | |
| 1162 | |
| 1163 // The views created here will be destroyed when the ExternalTabContainer | |
| 1164 // widget is torn down. | |
| 1165 external_tab_view_ = new views::View(); | |
| 1166 | |
| 1167 InfoBarContainerView* info_bar_container = new InfoBarContainerView(this); | |
| 1168 info_bar_container->ChangeTabContents(tab_contents_->infobar_tab_helper()); | |
| 1169 | |
| 1170 views::GridLayout* layout = new views::GridLayout(external_tab_view_); | |
| 1171 // Give this column an identifier of 0. | |
| 1172 views::ColumnSet* columns = layout->AddColumnSet(0); | |
| 1173 columns->AddColumn(views::GridLayout::FILL, | |
| 1174 views::GridLayout::FILL, | |
| 1175 1, | |
| 1176 views::GridLayout::USE_PREF, | |
| 1177 0, | |
| 1178 0); | |
| 1179 | |
| 1180 external_tab_view_->SetLayoutManager(layout); | |
| 1181 | |
| 1182 layout->StartRow(0, 0); | |
| 1183 layout->AddView(info_bar_container); | |
| 1184 layout->StartRow(1, 0); | |
| 1185 layout->AddView(tab_contents_container_); | |
| 1186 GetWidget()->SetContentsView(external_tab_view_); | |
| 1187 // Note that SetTabContents must be called after AddChildView is called | |
| 1188 tab_contents_container_->ChangeWebContents(web_contents()); | |
| 1189 } | |
| 1190 | |
| 1191 TemporaryPopupExternalTabContainer::TemporaryPopupExternalTabContainer( | |
| 1192 AutomationProvider* automation, | |
| 1193 AutomationResourceMessageFilter* filter) | |
| 1194 : ExternalTabContainer(automation, filter) { | |
| 1195 } | |
| 1196 | |
| 1197 TemporaryPopupExternalTabContainer::~TemporaryPopupExternalTabContainer() { | |
| 1198 DVLOG(1) << __FUNCTION__; | |
| 1199 } | |
| 1200 | |
| 1201 WebContents* TemporaryPopupExternalTabContainer::OpenURLFromTab( | |
| 1202 WebContents* source, | |
| 1203 const OpenURLParams& params) { | |
| 1204 if (!automation_) | |
| 1205 return NULL; | |
| 1206 | |
| 1207 OpenURLParams forward_params = params; | |
| 1208 if (params.disposition == CURRENT_TAB) { | |
| 1209 DCHECK(route_all_top_level_navigations_); | |
| 1210 forward_params.disposition = NEW_FOREGROUND_TAB; | |
| 1211 } | |
| 1212 WebContents* new_contents = | |
| 1213 ExternalTabContainer::OpenURLFromTab(source, forward_params); | |
| 1214 // support only one navigation for a dummy tab before it is killed. | |
| 1215 ::DestroyWindow(GetNativeView()); | |
| 1216 return new_contents; | |
| 1217 } | |
| OLD | NEW |