blob: 4bfeff2fd3ecef47757431f35e43f637de298eaf [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome_frame/external_tab.h"
#include "base/singleton.h"
#include "base/tracked.h"
#include "base/task.h"
#include "base/waitable_event.h"
#include "chrome/test/automation/automation_messages.h"
#include "chrome_frame/utils.h"
DISABLE_RUNNABLE_METHOD_REFCOUNT(ExternalTabProxy);
DISABLE_RUNNABLE_METHOD_REFCOUNT(UIDelegate);
namespace {
Singleton<ChromeProxyFactory> g_proxy_factory;
struct UserDataHolder : public SyncMessageContext {
explicit UserDataHolder(void* p) : data(p) {}
void* data;
};
}
ExternalTabProxy::ExternalTabProxy() : state_(NONE), tab_(0), tab_wnd_(NULL),
chrome_wnd_(NULL), proxy_factory_(g_proxy_factory.get()), proxy_(NULL),
ui_delegate_(NULL) {
}
ExternalTabProxy::~ExternalTabProxy() {
Destroy();
}
void ExternalTabProxy::Init() {
if (m_hWnd == NULL) {
// Create a window on the UI thread for marshaling messages back and forth
// from the IPC thread. This window cannot be a message only window as the
// external chrome tab window initially is created as a child of this window
CWindowImpl<ExternalTabProxy>::Create(GetDesktopWindow(), NULL, NULL,
WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_TOOLWINDOW);
DCHECK(m_hWnd != NULL);
ui_.SetWindow(m_hWnd, WM_APP + 6);
}
}
void ExternalTabProxy::Destroy() {
DCHECK(NULL == done_.get());
// TODO(stoyan): Should we release proxy first and then destroy the window
// (parent of the chrome window) or the other way around?
if (state_ != NONE) {
done_.reset(new base::WaitableEvent(true, false));
proxy_factory_->ReleaseProxy(this, tab_params_.proxy_params.profile);
done_->Wait();
done_.reset(NULL);
state_ = NONE;
proxy_ = NULL;
tab_ = 0;
CWindowImpl<ExternalTabProxy>::DestroyWindow();
tab_wnd_ = NULL;
chrome_wnd_ = NULL;
// We shall tell the TaskMarshaller to delete queued tasks.
// ui_.DeleteAll();
}
}
void ExternalTabProxy::CreateTab(const CreateTabParams& create_params,
UIDelegate* delegate) {
DCHECK(ui_delegate_ == NULL);
DCHECK_EQ(NONE, state_);
// Create host window if needed.
Init();
ui_delegate_ = delegate;
// TODO(stoyan): Shall we check the CanNavigate(create_params.url)?
tab_params_ = create_params;
state_ = INIT_IN_PROGRESS;
proxy_factory_->GetProxy(this, create_params.proxy_params);
}
void ExternalTabProxy::Connected(ChromeProxy* proxy) {
// in ipc thread
ui_.PostTask(FROM_HERE, NewRunnableMethod(this,
&ExternalTabProxy::UiConnected, proxy));
}
void ExternalTabProxy::UiConnected(ChromeProxy* proxy) {
proxy_ = proxy;
IPC::ExternalTabSettings settings;
settings.parent = m_hWnd;
settings.style = WS_CHILD;
settings.is_off_the_record = tab_params_.is_incognito;
// TODO(stoyan): FIX this.
settings.load_requests_via_automation = true;
// TODO(stoyan): FIX this.
settings.handle_top_level_requests = true;
settings.initial_url = tab_params_.url;
settings.referrer = tab_params_.referrer;
// Infobars are disabled in widget mode.
settings.infobars_enabled = !tab_params_.is_widget_mode;
// TODO(stoyan): FIX this.
settings.route_all_top_level_navigations = false;
state_ = CREATE_TAB_IN_PROGRESS;
proxy->CreateTab(this, settings);
}
void ExternalTabProxy::Disconnected() {
// in ipc thread
DCHECK(done_.get() != NULL);
done_->Signal();
}
void ExternalTabProxy::PeerLost(ChromeProxy* proxy, DisconnectReason reason) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(this, &ExternalTabProxy::UiPeerLost,
proxy, reason));
}
void ExternalTabProxy::UiPeerLost(ChromeProxy* proxy, DisconnectReason reason) {
// TODO(stoyan):
}
void ExternalTabProxy::Navigate(const std::string& url,
const std::string& referrer, bool is_privileged) {
// in ui thread
// Catch invalid URLs early. Can we allow this navigation to happen?
GURL parsed_url(url);
if (!CanNavigate(parsed_url, security_manager_, is_privileged)) {
DLOG(ERROR) << __FUNCTION__ << " Not allowing navigation to: " << url;
return;
}
GURL parsed_referrer(referrer);
// If we are still establishing channel, simply replace the params
if (state_ == INIT_IN_PROGRESS) {
tab_params_.url = parsed_url;
tab_params_.referrer = parsed_referrer;
}
// Ah! Too late. Wait to get tab handle and then navigate.
if (state_ == CREATE_TAB_IN_PROGRESS) {
pending_navigation_.Set(parsed_url, parsed_referrer);
}
if (state_ == READY) {
proxy_->Tab_Navigate(tab_, parsed_url, parsed_referrer);
}
}
void ExternalTabProxy::ConnectToExternalTab(uint64 external_tab_cookie) {
proxy_->ConnectTab(this, m_hWnd, external_tab_cookie);
}
void ExternalTabProxy::BlockExternalTab(uint64 cookie) {
proxy_->BlockTab(cookie);
}
void ExternalTabProxy::SetZoomLevel(PageZoom::Function zoom_level) {
proxy_->Tab_Zoom(tab_, zoom_level);
}
void ExternalTabProxy::NavigateToIndex(int index) {
CHECK(0);
}
void ExternalTabProxy::ForwardMessageFromExternalHost(
const std::string& message, const std::string& origin,
const std::string& target) {
proxy_->Tab_PostMessage(tab_, message, origin, target);
}
void ExternalTabProxy::SetEnableExtensionAutomation(
const std::vector<std::string>& functions_enabled) {
proxy_->Tab_SetEnableExtensionAutomation(tab_, functions_enabled);
}
void ExternalTabProxy::InstallExtension(const FilePath& crx_path,
void* user_data) {
proxy_->InstallExtension(this, crx_path, new UserDataHolder(user_data));
}
void ExternalTabProxy::LoadExpandedExtension(const FilePath& path,
void* user_data) {
proxy_->LoadExtension(this, path, new UserDataHolder(user_data));
}
void ExternalTabProxy::GetEnabledExtensions(void* user_data) {
proxy_->GetEnabledExtensions(this, new UserDataHolder(user_data));
}
void ExternalTabProxy::ChromeFrameHostMoved() {
proxy_->Tab_OnHostMoved(tab_);
}
//////////////////////////////////////////////////////////////////////////
void ExternalTabProxy::UiCompleted_CreateTab(bool success, HWND chrome_window,
HWND tab_window, int tab_handle) {
if (success) {
state_ = READY;
tab_ = tab_handle;
tab_wnd_ = tab_window;
chrome_wnd_ = chrome_window;
// If a navigation request came while tab creation was in progress -
// go ahead and navigate.
if (pending_navigation_.url.is_valid())
proxy_->Tab_Navigate(tab_, pending_navigation_.url,
pending_navigation_.referrer);
}
}
void ExternalTabProxy::Completed_CreateTab(bool success, HWND chrome_wnd,
HWND tab_window, int tab_handle) {
// in ipc_thread.
ui_.PostTask(FROM_HERE, NewRunnableMethod(this,
&ExternalTabProxy::UiCompleted_CreateTab,
success, chrome_wnd, tab_window, tab_handle));
}
void ExternalTabProxy::Completed_ConnectToTab(bool success,
HWND chrome_window, HWND tab_window, int tab_handle) {
CHECK(0);
}
void ExternalTabProxy::Completed_Navigate(bool success,
enum AutomationMsg_NavigationResponseValues res) {
// ipc_thread;
CHECK(0);
}
void ExternalTabProxy::Completed_InstallExtension(bool success,
enum AutomationMsg_ExtensionResponseValues res, SyncMessageContext* ctx) {
CHECK(0);
}
void ExternalTabProxy::Completed_LoadExpandedExtension(bool success,
enum AutomationMsg_ExtensionResponseValues res, SyncMessageContext* ctx) {
CHECK(0);
}
void ExternalTabProxy::Completed_GetEnabledExtensions(bool success,
const std::vector<FilePath>* extensions) {
CHECK(0);
}
void ExternalTabProxy::NavigationStateChanged(int flags,
const IPC::NavigationInfo& nav_info) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_,
&UIDelegate::OnNavigationStateChanged, flags, nav_info));
}
void ExternalTabProxy::UpdateTargetUrl(const std::wstring& url) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_,
&UIDelegate::OnUpdateTargetUrl, url));
}
void ExternalTabProxy::TabLoaded(const GURL& url) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_,
&UIDelegate::OnLoad, url));
}
void ExternalTabProxy::MessageToHost(const std::string& message,
const std::string& origin,
const std::string& target) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_,
&UIDelegate::OnMessageFromChromeFrame, message, origin, target));
}
void ExternalTabProxy::HandleAccelerator(const MSG& accel_message) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_,
&UIDelegate::OnHandleAccelerator, accel_message));
}
void ExternalTabProxy::HandleContextMenu(HANDLE menu_handle, int align_flags,
const IPC::ContextMenuParams& params) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_,
&UIDelegate::OnHandleContextMenu, menu_handle, align_flags, params));
}
void ExternalTabProxy::TabbedOut(bool reverse) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_,
&UIDelegate::OnTabbedOut, reverse));
}
void ExternalTabProxy::GoToHistoryOffset(int offset) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_,
&UIDelegate::OnGoToHistoryOffset, offset));
}
void ExternalTabProxy::OpenURL(const GURL& url_to_open, const GURL& referrer,
int open_disposition) {
ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_,
&UIDelegate::OnOpenURL, url_to_open, referrer, open_disposition));
}
void ExternalTabProxy::NavigationFailed(int error_code, const GURL& gurl) {
// TODO(stoyan):
}
void ExternalTabProxy::DidNavigate(const IPC::NavigationInfo& navigation_info) {
// TODO(stoyan):
}
void ExternalTabProxy::Network_Start(
int request_id, const IPC::AutomationURLRequest& request_info) {
// TODO(stoyan): url_fetcher_.Start();
}
void ExternalTabProxy::Network_Read(int request_id, int bytes_to_read) {
// TODO(stoyan): url_fetcher_.Read();
}
void ExternalTabProxy::Network_End(int request_id, const URLRequestStatus& s) {
// TODO(stoyan):
}
void ExternalTabProxy::Network_DownloadInHost(int request_id) {
// TODO(stoyan):
}
void ExternalTabProxy::GetCookies(const GURL& url, int cookie_id) {
// TODO(stoyan):
}
void ExternalTabProxy::SetCookie(const GURL& url, const std::string& cookie) {
// TODO(stoyan):
}
void ExternalTabProxy::TabClosed() {
// TODO(stoyan):
}
void ExternalTabProxy::AttachTab(
const IPC::AttachExternalTabParams& attach_params) {
// TODO(stoyan):
}