summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome_frame/chrome_active_document.cc251
-rw-r--r--chrome_frame/chrome_active_document.h52
-rw-r--r--chrome_frame/chrome_frame_activex.cc70
-rw-r--r--chrome_frame/chrome_frame_activex.h26
-rw-r--r--chrome_frame/chrome_frame_activex_base.h83
-rw-r--r--chrome_frame/chrome_frame_automation.cc3
-rw-r--r--chrome_frame/extra_system_apis.h28
-rw-r--r--chrome_frame/html_private_window_impl.h66
-rw-r--r--chrome_frame/html_window_impl.h385
-rw-r--r--chrome_frame/test/chrome_frame_test_utils.cc11
-rw-r--r--chrome_frame/test/chrome_frame_unittests.cc216
-rw-r--r--chrome_frame/test/chrome_frame_unittests.h83
-rw-r--r--chrome_frame/test/data/anchor.html51
-rw-r--r--chrome_frame/test/data/frame_test.html18
-rw-r--r--chrome_frame/test/data/sub_frame1.html15
-rw-r--r--chrome_frame/test/data/sub_frame2.html15
-rw-r--r--chrome_frame/test/data/sub_frame3.html15
-rw-r--r--chrome_frame/test/data/sub_frame4.html15
-rw-r--r--chrome_frame/test/perf/chrome_frame_perftest.cc66
-rw-r--r--chrome_frame/test_utils.h39
20 files changed, 1252 insertions, 256 deletions
diff --git a/chrome_frame/chrome_active_document.cc b/chrome_frame/chrome_active_document.cc
index 2842e01..56b13be 100644
--- a/chrome_frame/chrome_active_document.cc
+++ b/chrome_frame/chrome_active_document.cc
@@ -7,6 +7,7 @@
#include <hlink.h>
#include <htiface.h>
+#include <initguid.h>
#include <mshtmcid.h>
#include <shdeprecated.h>
#include <shlguid.h>
@@ -42,6 +43,10 @@ static const wchar_t kUseChromeNetworking[] = L"UseChromeNetworking";
static const wchar_t kHandleTopLevelRequests[] =
L"HandleTopLevelRequests";
+DEFINE_GUID(CGID_DocHostCmdPriv, 0x000214D4L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0,
+ 0x46);
+
+
base::ThreadLocalPointer<ChromeActiveDocument> g_active_doc_cache;
bool g_first_launch_by_process_ = true;
@@ -49,6 +54,7 @@ bool g_first_launch_by_process_ = true;
ChromeActiveDocument::ChromeActiveDocument()
: first_navigation_(true),
is_automation_client_reused_(false) {
+ memset(&navigation_info_, 0, sizeof(navigation_info_));
}
HRESULT ChromeActiveDocument::FinalConstruct() {
@@ -179,6 +185,20 @@ STDMETHODIMP ChromeActiveDocument::Load(BOOL fully_avalable,
if (NULL == moniker_name) {
return E_INVALIDARG;
}
+
+ ScopedComPtr<IOleClientSite> client_site;
+ if (bind_context) {
+ ScopedComPtr<IUnknown> site;
+ bind_context->GetObjectParam(SZ_HTML_CLIENTSITE_OBJECTPARAM,
+ site.Receive());
+ if (site)
+ client_site.QueryFrom(site);
+ }
+
+ if (client_site) {
+ SetClientSite(client_site);
+ }
+
CComHeapPtr<WCHAR> display_name;
moniker_name->GetDisplayName(bind_context, NULL, &display_name);
std::wstring url = display_name;
@@ -273,6 +293,72 @@ STDMETHODIMP ChromeActiveDocument::Exec(const GUID* cmd_group_guid,
return OLECMDERR_E_NOTSUPPORTED;
}
+STDMETHODIMP ChromeActiveDocument::LoadHistory(IStream* stream,
+ IBindCtx* bind_context) {
+ // Read notes in ChromeActiveDocument::SaveHistory
+ DCHECK(stream);
+ LARGE_INTEGER offset = {0};
+ ULARGE_INTEGER cur_pos = {0};
+ STATSTG statstg = {0};
+
+ stream->Seek(offset, STREAM_SEEK_CUR, &cur_pos);
+ stream->Stat(&statstg, STATFLAG_NONAME);
+
+ DWORD url_size = statstg.cbSize.LowPart - cur_pos.LowPart;
+ ScopedBstr url_bstr;
+ DWORD bytes_read = 0;
+ stream->Read(url_bstr.AllocateBytes(url_size), url_size, &bytes_read);
+ std::wstring url(url_bstr);
+
+ bool is_new_navigation = true;
+ bool is_chrome_protocol = false;
+
+ if (!ParseUrl(url, &is_new_navigation, &is_chrome_protocol, &url)) {
+ DLOG(WARNING) << __FUNCTION__ << " Failed to parse url:" << url;
+ return E_INVALIDARG;
+ }
+
+ if (!LaunchUrl(url, is_new_navigation)) {
+ NOTREACHED() << __FUNCTION__ << " Failed to launch url:" << url;
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP ChromeActiveDocument::SaveHistory(IStream* stream) {
+ // TODO(sanjeevr): We need to fetch the entire list of navigation entries
+ // from Chrome and persist it in the stream. And in LoadHistory we need to
+ // pass this list back to Chrome which will recreate the list. This will allow
+ // Back-Forward navigation to anchors to work correctly when we navigate to a
+ // page outside of ChromeFrame and then come back.
+ if (!stream) {
+ NOTREACHED();
+ return E_INVALIDARG;
+ }
+
+ LARGE_INTEGER offset = {0};
+ ULARGE_INTEGER new_pos = {0};
+ DWORD written = 0;
+ std::wstring url = UTF8ToWide(navigation_info_.url.spec());
+ return stream->Write(url.c_str(), (url.length() + 1) * sizeof(wchar_t),
+ &written);
+}
+
+STDMETHODIMP ChromeActiveDocument::SetPositionCookie(DWORD position_cookie) {
+ int index = static_cast<int>(position_cookie);
+ navigation_info_.navigation_index = index;
+ automation_client_->NavigateToIndex(index);
+ return S_OK;
+}
+
+STDMETHODIMP ChromeActiveDocument::GetPositionCookie(DWORD* position_cookie) {
+ if (!position_cookie)
+ return E_INVALIDARG;
+
+ *position_cookie = navigation_info_.navigation_index;
+ return S_OK;
+}
+
STDMETHODIMP ChromeActiveDocument::GetUrlForEvents(BSTR* url) {
if (NULL == url) {
return E_POINTER;
@@ -281,6 +367,10 @@ STDMETHODIMP ChromeActiveDocument::GetUrlForEvents(BSTR* url) {
return S_OK;
}
+STDMETHODIMP ChromeActiveDocument::GetAddressBarUrl(BSTR* url) {
+ return GetUrlForEvents(url);
+}
+
HRESULT ChromeActiveDocument::IOleObject_SetClientSite(
IOleClientSite* client_site) {
if (client_site == NULL) {
@@ -301,7 +391,11 @@ HRESULT ChromeActiveDocument::IOleObject_SetClientSite(
doc_site_.Release();
in_place_frame_.Release();
}
- return Base::IOleObject_SetClientSite(client_site);
+
+ if (client_site != m_spClientSite)
+ return Base::IOleObject_SetClientSite(client_site);
+
+ return S_OK;
}
@@ -363,9 +457,6 @@ HRESULT ChromeActiveDocument::ActiveXDocActivate(LONG verb) {
}
}
m_spClientSite->ShowObject();
- // Inform IE about the zone for this URL. We do this here as we need to the
- // IOleInPlaceSite interface to be setup.
- IEExec(&CGID_Explorer, SBCMDID_MIXEDZONE, 0, NULL, NULL);
return S_OK;
}
@@ -442,30 +533,21 @@ void ChromeActiveDocument::OnDidNavigate(int tab_handle,
void ChromeActiveDocument::UpdateNavigationState(
const IPC::NavigationInfo& new_navigation_info) {
+ HRESULT hr = S_OK;
bool is_title_changed = (navigation_info_.title != new_navigation_info.title);
- bool is_url_changed = (navigation_info_.url.is_valid() &&
- (navigation_info_.url != new_navigation_info.url));
bool is_ssl_state_changed =
(navigation_info_.security_style != new_navigation_info.security_style) ||
(navigation_info_.has_mixed_content !=
new_navigation_info.has_mixed_content);
- navigation_info_ = new_navigation_info;
-
- if (is_title_changed) {
- ScopedVariant title(navigation_info_.title.c_str());
- IEExec(NULL, OLECMDID_SETTITLE, OLECMDEXECOPT_DONTPROMPTUSER,
- title.AsInput(), NULL);
- }
-
if (is_ssl_state_changed) {
int lock_status = SECURELOCK_SET_UNSECURE;
- switch (navigation_info_.security_style) {
+ switch (new_navigation_info.security_style) {
case SECURITY_STYLE_AUTHENTICATION_BROKEN:
lock_status = SECURELOCK_SET_SECUREUNKNOWNBIT;
break;
case SECURITY_STYLE_AUTHENTICATED:
- lock_status = navigation_info_.has_mixed_content ?
+ lock_status = new_navigation_info.has_mixed_content ?
SECURELOCK_SET_MIXED : SECURELOCK_SET_SECUREUNKNOWNBIT;
break;
default:
@@ -477,32 +559,78 @@ void ChromeActiveDocument::UpdateNavigationState(
OLECMDEXECOPT_DODEFAULT, secure_lock_status.AsInput(), NULL);
}
- if (navigation_info_.url.is_valid() &&
- (is_url_changed || url_.Length() == 0)) {
- url_.Allocate(UTF8ToWide(navigation_info_.url.spec()).c_str());
- // Now call the FireNavigateCompleteEvent which makes IE update the text
- // in the address-bar. We call the FireBeforeNavigateComplete2Event and
- // FireDocumentComplete event just for completeness sake. If some BHO
- // chooses to cancel the navigation in the OnBeforeNavigate2 handler
- // we will ignore the cancellation request.
+ // Ideally all navigations should come to Chrome Frame so that we can call
+ // BeforeNavigate2 on installed BHOs and give them a chance to cancel the
+ // navigation. However, in practice what happens is as below:
+ // The very first navigation that happens in CF happens via a Load or a
+ // LoadHistory call. In this case, IE already has the correct information for
+ // its travel log as well address bar. For other internal navigations (navs
+ // that only happen within Chrome such as anchor navigations) we need to
+ // update IE's internal state after the fact. In the case of internal
+ // navigations, we notify the BHOs but ignore the should_cancel flag.
+ bool is_internal_navigation = (new_navigation_info.navigation_index > 0) &&
+ (new_navigation_info.navigation_index !=
+ navigation_info_.navigation_index);
- // Todo(joshia): investigate if there's a better way to set URL in the
- // address bar
+ if (new_navigation_info.url.is_valid()) {
+ url_.Allocate(UTF8ToWide(new_navigation_info.url.spec()).c_str());
+ }
+
+ if (is_internal_navigation) {
+ ScopedComPtr<IDocObjectService> doc_object_svc;
ScopedComPtr<IWebBrowserEventsService> web_browser_events_svc;
DoQueryService(__uuidof(web_browser_events_svc), m_spClientSite,
web_browser_events_svc.Receive());
+ DCHECK(web_browser_events_svc);
if (web_browser_events_svc) {
- // TODO(joshia): maybe we should call FireBeforeNavigate2Event in
- // ChromeActiveDocument::Load and abort if cancelled.
VARIANT_BOOL should_cancel = VARIANT_FALSE;
web_browser_events_svc->FireBeforeNavigate2Event(&should_cancel);
+ }
+
+ // We need to tell IE that we support navigation so that IE will query us
+ // for IPersistHistory and call GetPositionCookie to save our navigation
+ // index.
+ ScopedVariant html_window(static_cast<IUnknown*>(
+ static_cast<IHTMLWindow2*>(this)));
+ IEExec(&CGID_DocHostCmdPriv, DOCHOST_DOCCANNAVIGATE, 0,
+ html_window.AsInput(), NULL);
+
+ // We pass the HLNF_INTERNALJUMP flag to INTERNAL_CMDID_FINALIZE_TRAVEL_LOG
+ // since we want to make IE treat all internal navigations within this page
+ // (including anchor navigations and subframe navigations) as anchor
+ // navigations. This will ensure that IE calls GetPositionCookie
+ // to save the current position cookie in the travel log and then call
+ // SetPositionCookie when the user hits Back/Forward to come back here.
+ ScopedVariant internal_navigation(HLNF_INTERNALJUMP);
+ IEExec(&CGID_Explorer, INTERNAL_CMDID_FINALIZE_TRAVEL_LOG, 0,
+ internal_navigation.AsInput(), NULL);
+
+ // We no longer need to lie to IE. If we lie persistently to IE, then
+ // IE reuses us for new navigations.
+ IEExec(&CGID_DocHostCmdPriv, DOCHOST_DOCCANNAVIGATE, 0, NULL, NULL);
+
+ if (doc_object_svc) {
+ // Now call the FireNavigateCompleteEvent which makes IE update the text
+ // in the address-bar.
+ doc_object_svc->FireNavigateComplete2(this, 0);
+ doc_object_svc->FireDocumentComplete(this, 0);
+ } else if (web_browser_events_svc) {
web_browser_events_svc->FireNavigateComplete2Event();
- if (VARIANT_TRUE != should_cancel) {
- web_browser_events_svc->FireDocumentCompleteEvent();
- }
+ web_browser_events_svc->FireDocumentCompleteEvent();
}
}
+ if (is_title_changed) {
+ ScopedVariant title(new_navigation_info.title.c_str());
+ IEExec(NULL, OLECMDID_SETTITLE, OLECMDEXECOPT_DONTPROMPTUSER,
+ title.AsInput(), NULL);
+ }
+
+ // It is important that we only update the navigation_info_ after we have
+ // finalized the travel log. This is because IE will ask for information
+ // such as navigation index when the travel log is finalized and we need
+ // supply the old index and not the new one.
+ navigation_info_ = new_navigation_info;
// Update the IE zone here. Ideally we would like to do it when the active
// document is activated. However that does not work at times as the frame we
// get there is not the actual frame which handles the command.
@@ -556,23 +684,12 @@ void ChromeActiveDocument::OnOpenURL(int tab_handle,
Base::OnOpenURL(tab_handle, url_to_open, referrer, open_disposition);
}
-void ChromeActiveDocument::OnLoad(int tab_handle, const GURL& url) {
- if (ready_state_ < READYSTATE_COMPLETE) {
- ready_state_ = READYSTATE_COMPLETE;
- FireOnChanged(DISPID_READYSTATE);
- }
-}
-
bool ChromeActiveDocument::PreProcessContextMenu(HMENU menu) {
ScopedComPtr<IBrowserService> browser_service;
ScopedComPtr<ITravelLog> travel_log;
-
- DoQueryService(SID_SShellBrowser, m_spClientSite, browser_service.Receive());
- if (!browser_service)
- return true;
-
- browser_service->GetTravelLog(travel_log.Receive());
- if (!travel_log)
+ GetBrowserServiceAndTravelLog(browser_service.Receive(),
+ travel_log.Receive());
+ if (!browser_service || !travel_log)
return true;
if (SUCCEEDED(travel_log->GetTravelEntry(browser_service, TLOG_BACK, NULL))) {
@@ -581,7 +698,6 @@ bool ChromeActiveDocument::PreProcessContextMenu(HMENU menu) {
EnableMenuItem(menu, IDS_CONTENT_CONTEXT_BACK, MF_BYCOMMAND | MFS_DISABLED);
}
-
if (SUCCEEDED(travel_log->GetTravelEntry(browser_service, TLOG_FORE, NULL))) {
EnableMenuItem(menu, IDS_CONTENT_CONTEXT_FORWARD,
MF_BYCOMMAND | MF_ENABLED);
@@ -731,10 +847,9 @@ bool ChromeActiveDocument::LaunchUrl(const std::wstring& url,
std::string referrer;
Bho* chrome_frame_bho = Bho::GetCurrentThreadBhoInstance();
- DCHECK(chrome_frame_bho != NULL);
- if (chrome_frame_bho) {
+ if (chrome_frame_bho)
referrer = chrome_frame_bho->referrer();
- }
+
if (!automation_client_->InitiateNavigation(utf8_url,
referrer,
is_privileged_)) {
@@ -806,14 +921,36 @@ HRESULT ChromeActiveDocument::SetPageFontSize(const GUID* cmd_group_guid,
void ChromeActiveDocument::OnGoToHistoryEntryOffset(int tab_handle,
int offset) {
- DLOG(INFO) << "GoToHistoryEntryOffset " << offset;
+ DLOG(INFO) << __FUNCTION__ << " - offset:" << offset;
+
ScopedComPtr<IBrowserService> browser_service;
- DoQueryService(SID_SShellBrowser, m_spClientSite, browser_service.Receive());
- if (browser_service) {
- ScopedComPtr<ITravelLog> travel_log;
- browser_service->GetTravelLog(travel_log.Receive());
- if (travel_log) {
- travel_log->Travel(browser_service, offset);
- }
+ ScopedComPtr<ITravelLog> travel_log;
+ GetBrowserServiceAndTravelLog(browser_service.Receive(),
+ travel_log.Receive());
+
+ if (browser_service && travel_log)
+ travel_log->Travel(browser_service, offset);
+}
+
+HRESULT ChromeActiveDocument::GetBrowserServiceAndTravelLog(
+ IBrowserService** browser_service, ITravelLog** travel_log) {
+ DCHECK(browser_service || travel_log);
+ ScopedComPtr<IBrowserService> browser_service_local;
+ HRESULT hr = DoQueryService(SID_SShellBrowser, m_spClientSite,
+ browser_service_local.Receive());
+ if (!browser_service_local) {
+ NOTREACHED() << "DoQueryService for IBrowserService failed: " << hr;
+ return hr;
}
+
+ if (travel_log) {
+ hr = browser_service_local->GetTravelLog(travel_log);
+ DLOG_IF(INFO, !travel_log) << "browser_service->GetTravelLog failed: "
+ << hr;
+ }
+
+ if (browser_service)
+ *browser_service = browser_service_local.Detach();
+
+ return hr;
}
diff --git a/chrome_frame/chrome_active_document.h b/chrome_frame/chrome_active_document.h
index ee2cf6e..103eb49 100644
--- a/chrome_frame/chrome_active_document.h
+++ b/chrome_frame/chrome_active_document.h
@@ -10,6 +10,7 @@
#include <atlctl.h>
#include <map>
#include <mshtmcid.h>
+#include <perhist.h>
#include "base/scoped_ptr.h"
#include "base/scoped_comptr_win.h"
@@ -18,6 +19,8 @@
#include "chrome_frame/chrome_frame_activex_base.h"
#include "chrome_frame/com_type_info_holder.h"
#include "chrome_frame/find_dialog.h"
+#include "chrome_frame/html_private_window_impl.h"
+#include "chrome_frame/html_window_impl.h"
#include "chrome_frame/in_place_menu.h"
#include "chrome_frame/ole_document_impl.h"
#include "chrome_frame/resource.h"
@@ -54,6 +57,17 @@ class ChromeActiveDocument;
#define SBCMDID_MIXEDZONE 39
#endif // SBCMDID_MIXEDZONE
+// From MSDN:
+// Controlling Navigation: The fact that a document can navigate on its own
+// implies that it will also take care of updating the navigation history.
+// In Internet Explorer 6 and later, the DocObject can indicate to the client
+// site that it can navigate using CGID_DocHostCmdPriv (a privately defined
+// command group GUID) and the DOCHOST_DOCCANNAVIGATE command. A pointer to
+// the object that implements the IHTMLWindow2 interface is passed with the
+// command in the VARIANTARG* parameter pvaIn. (Set pvaIn to NULL if the
+// document cannot perform its own navigation.)
+#define DOCHOST_DOCCANNAVIGATE (0)
+
// This macro should be defined in the public section of the class.
#define BEGIN_EXEC_COMMAND_MAP(theClass) \
public: \
@@ -97,14 +111,17 @@ class ChromeActiveDocument;
// Chrome.exe (via the Chrome IPC-based automation mechanism) for the actual
// rendering
class ATL_NO_VTABLE ChromeActiveDocument
- : public ChromeFrameActivexBase<ChromeActiveDocument,
- CLSID_ChromeActiveDocument>,
- public IOleDocumentImpl<ChromeActiveDocument>,
- public IOleDocumentViewImpl<ChromeActiveDocument>,
- public IPersistMoniker,
- public IOleCommandTarget,
- public InPlaceMenu<ChromeActiveDocument>,
- public IWebBrowserEventsUrlService {
+ : public ChromeFrameActivexBase<ChromeActiveDocument,
+ CLSID_ChromeActiveDocument>,
+ public IOleDocumentImpl<ChromeActiveDocument>,
+ public IOleDocumentViewImpl<ChromeActiveDocument>,
+ public IPersistMoniker,
+ public IOleCommandTarget,
+ public InPlaceMenu<ChromeActiveDocument>,
+ public IWebBrowserEventsUrlService,
+ public IPersistHistory,
+ public HTMLWindowImpl<IHTMLWindow2>,
+ public HTMLPrivateWindowImpl<IHTMLPrivateWindow> {
public:
typedef ChromeFrameActivexBase<ChromeActiveDocument,
CLSID_ChromeActiveDocument> Base;
@@ -119,6 +136,11 @@ BEGIN_COM_MAP(ChromeActiveDocument)
COM_INTERFACE_ENTRY(IPersistMoniker)
COM_INTERFACE_ENTRY(IOleCommandTarget)
COM_INTERFACE_ENTRY(IWebBrowserEventsUrlService)
+ COM_INTERFACE_ENTRY(IPersist)
+ COM_INTERFACE_ENTRY(IPersistHistory)
+ COM_INTERFACE_ENTRY(IHTMLFramesCollection2)
+ COM_INTERFACE_ENTRY(IHTMLWindow2)
+ COM_INTERFACE_ENTRY(IHTMLPrivateWindow)
COM_INTERFACE_ENTRY_CHAIN(Base)
END_COM_MAP()
@@ -195,9 +217,18 @@ END_EXEC_COMMAND_MAP()
VARIANT* in_args,
VARIANT* out_args);
+ // IPersistHistory
+ STDMETHOD(LoadHistory)(IStream* stream, IBindCtx* bind_context);
+ STDMETHOD(SaveHistory)(IStream* stream);
+ STDMETHOD(SetPositionCookie)(DWORD position_cookie);
+ STDMETHOD(GetPositionCookie)(DWORD* position_cookie);
+
// IWebBrowserEventsUrlService methods
STDMETHOD(GetUrlForEvents)(BSTR* url);
+ // IHTMLPrivateWindow methods
+ STDMETHOD(GetAddressBarUrl)(BSTR* url);
+
// ChromeFrameActivexBase overrides
HRESULT IOleObject_SetClientSite(IOleClientSite* client_site);
@@ -216,7 +247,6 @@ END_EXEC_COMMAND_MAP()
virtual void OnOpenURL(int tab_handle, const GURL& url_to_open,
const GURL& referrer, int open_disposition);
- virtual void OnLoad(int tab_handle, const GURL& url);
virtual void OnGoToHistoryEntryOffset(int tab_handle, int offset);
// A helper method that updates our internal navigation state
@@ -262,6 +292,10 @@ END_EXEC_COMMAND_MAP()
VARIANT* in_args,
VARIANT* out_args);
+ // Get the travel log from the client site
+ HRESULT GetBrowserServiceAndTravelLog(IBrowserService** browser_service,
+ ITravelLog** travel_log);
+
protected:
typedef std::map<int, bool> EnabledCommandsMap;
diff --git a/chrome_frame/chrome_frame_activex.cc b/chrome_frame/chrome_frame_activex.cc
index 16f5dda..297b5ad 100644
--- a/chrome_frame/chrome_frame_activex.cc
+++ b/chrome_frame/chrome_frame_activex.cc
@@ -21,7 +21,6 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/tab_proxy.h"
#include "googleurl/src/gurl.h"
-#include "chrome_frame/com_message_event.h"
#include "chrome_frame/utils.h"
ChromeFrameActivex::ChromeFrameActivex() {
@@ -75,13 +74,7 @@ void ChromeFrameActivex::OnLoad(int tab_handle, const GURL& gurl) {
Fire_onload(event);
FireEvent(onload_, url);
-
- HRESULT hr = InvokeScriptFunction(onload_handler_, url);
-
- if (ready_state_ < READYSTATE_COMPLETE) {
- ready_state_ = READYSTATE_COMPLETE;
- FireOnChanged(DISPID_READYSTATE);
- }
+ Base::OnLoad(tab_handle, gurl);
}
void ChromeFrameActivex::OnLoadFailed(int error_code, const std::string& url) {
@@ -90,8 +83,7 @@ void ChromeFrameActivex::OnLoadFailed(int error_code, const std::string& url) {
Fire_onloaderror(event);
FireEvent(onloaderror_, url);
-
- HRESULT hr = InvokeScriptFunction(onerror_handler_, url);
+ Base::OnLoadFailed(error_code, url);
}
void ChromeFrameActivex::OnMessageFromChromeFrame(int tab_handle,
@@ -156,38 +148,6 @@ void ChromeFrameActivex::OnExtensionInstalled(
Fire_onextensionready(path_str, response);
}
-HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
- const std::string& param) {
- ScopedVariant script_arg(UTF8ToWide(param.c_str()).c_str());
- return InvokeScriptFunction(script_object, script_arg.AsInput());
-}
-
-HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
- VARIANT* param) {
- return InvokeScriptFunction(script_object, param, 1);
-}
-
-HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
- VARIANT* params,
- int param_count) {
- DCHECK(param_count >= 0);
- DCHECK(params);
-
- if (V_VT(&script_object) != VT_DISPATCH) {
- return S_FALSE;
- }
-
- CComPtr<IDispatch> script(script_object.pdispVal);
- HRESULT hr = script.InvokeN(static_cast<DISPID>(DISPID_VALUE),
- params,
- param_count);
- // 0x80020101 == SCRIPT_E_REPORTED.
- // When the script we're invoking has an error, we get this error back.
- DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101) << "Failed to invoke script";
-
- return hr;
-}
-
HRESULT ChromeFrameActivex::OnDraw(ATL_DRAWINFO& draw_info) { // NO_LINT
HRESULT hr = S_OK;
int dc_type = ::GetObjectType(draw_info.hicTargetDev);
@@ -437,32 +397,6 @@ HRESULT ChromeFrameActivex::CreateScriptBlockForEvent(
return hr;
}
-HRESULT ChromeFrameActivex::CreateDomEvent(const std::string& event_type,
- const std::string& data,
- const std::string& origin,
- IDispatch** event) {
- DCHECK(event_type.length() > 0);
- DCHECK(event != NULL);
-
- CComObject<ComMessageEvent>* ev = NULL;
- HRESULT hr = CComObject<ComMessageEvent>::CreateInstance(&ev);
- if (SUCCEEDED(hr)) {
- ev->AddRef();
-
- ScopedComPtr<IOleContainer> container;
- m_spClientSite->GetContainer(container.Receive());
- if (ev->Initialize(container, data, origin, event_type)) {
- *event = ev;
- } else {
- NOTREACHED() << "event->Initialize";
- ev->Release();
- hr = E_UNEXPECTED;
- }
- }
-
- return hr;
-}
-
void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
const std::string& arg) {
if (handlers.size()) {
diff --git a/chrome_frame/chrome_frame_activex.h b/chrome_frame/chrome_frame_activex.h
index 04169af..1acbc37 100644
--- a/chrome_frame/chrome_frame_activex.h
+++ b/chrome_frame/chrome_frame_activex.h
@@ -80,30 +80,22 @@ END_MSG_MAP()
STDMETHOD(put_src)(BSTR src);
protected:
+ // ChromeFrameDelegate overrides
virtual void OnLoad(int tab_handle, const GURL& url);
virtual void OnMessageFromChromeFrame(int tab_handle,
const std::string& message,
const std::string& origin,
const std::string& target);
+ virtual void OnLoadFailed(int error_code, const std::string& url);
+ virtual void OnAutomationServerLaunchFailed(
+ AutomationLaunchResult reason, const std::string& server_version);
+ virtual void OnExtensionInstalled(const FilePath& path,
+ void* user_data, AutomationMsg_ExtensionResponseValues response);
private:
-
LRESULT OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
BOOL& handled); // NO_LINT
- // ChromeFrameDelegate overrides
- virtual void ChromeFrameActivex::OnAutomationServerLaunchFailed(
- AutomationLaunchResult reason, const std::string& server_version);
- virtual void OnLoadFailed(int error_code, const std::string& url);
- virtual void OnExtensionInstalled(const FilePath& path,
- void* user_data, AutomationMsg_ExtensionResponseValues response);
-
- // Helper function to execute a function on a script IDispatch interface.
- HRESULT InvokeScriptFunction(const VARIANT& script, const std::string& param);
- HRESULT InvokeScriptFunction(const VARIANT& script, VARIANT* param);
- HRESULT InvokeScriptFunction(const VARIANT& script,
- VARIANT* param,
- int param_count);
HRESULT GetContainingDocument(IHTMLDocument2** doc);
HRESULT GetDocumentWindow(IHTMLWindow2** window);
@@ -119,12 +111,6 @@ END_MSG_MAP()
BSTR instance_id, BSTR script,
BSTR event_name);
- // Creates a new event object that supports the |data| property.
- // Note: you should supply an empty string for |origin| unless you're
- // creating a "message" event.
- HRESULT CreateDomEvent(const std::string& event_type, const std::string& data,
- const std::string& origin, IDispatch** event);
-
// Utility function that checks the size of the vector and if > 0 creates
// a variant for the string argument and forwards the call to the other
// FireEvent method.
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index 202f4d6..09ad669 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -37,6 +37,7 @@
#include "grit/chrome_frame_resources.h"
#include "grit/chrome_frame_strings.h"
#include "chrome_frame/chrome_frame_plugin.h"
+#include "chrome_frame/com_message_event.h"
#include "chrome_frame/com_type_info_holder.h"
#include "chrome_frame/urlmon_url_request.h"
@@ -318,6 +319,31 @@ END_MSG_MAP()
}
protected:
+ void OnLoad(int tab_handle, const GURL& url) {
+ if (ready_state_ < READYSTATE_COMPLETE) {
+ ready_state_ = READYSTATE_COMPLETE;
+ FireOnChanged(DISPID_READYSTATE);
+ }
+
+ HRESULT hr = InvokeScriptFunction(onload_handler_, url.spec());
+ }
+
+ void OnLoadFailed(int error_code, const std::string& url) {
+ HRESULT hr = InvokeScriptFunction(onerror_handler_, url);
+ }
+
+ void OnMessageFromChromeFrame(int tab_handle, const std::string& message,
+ const std::string& origin,
+ const std::string& target) {
+ ScopedComPtr<IDispatch> message_event;
+ if (SUCCEEDED(CreateDomEvent("message", message, origin,
+ message_event.Receive()))) {
+ ScopedVariant event_var;
+ event_var.Set(static_cast<IDispatch*>(message_event));
+ InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
+ }
+ }
+
virtual void OnTabbedOut(int tab_handle, bool reverse) {
DCHECK(m_bInPlaceActive);
@@ -883,6 +909,63 @@ END_MSG_MAP()
return hr;
}
+ // Creates a new event object that supports the |data| property.
+ // Note: you should supply an empty string for |origin| unless you're
+ // creating a "message" event.
+ HRESULT CreateDomEvent(const std::string& event_type, const std::string& data,
+ const std::string& origin, IDispatch** event) {
+ DCHECK(event_type.length() > 0);
+ DCHECK(event != NULL);
+
+ CComObject<ComMessageEvent>* ev = NULL;
+ HRESULT hr = CComObject<ComMessageEvent>::CreateInstance(&ev);
+ if (SUCCEEDED(hr)) {
+ ev->AddRef();
+
+ ScopedComPtr<IOleContainer> container;
+ m_spClientSite->GetContainer(container.Receive());
+ if (ev->Initialize(container, data, origin, event_type)) {
+ *event = ev;
+ } else {
+ NOTREACHED() << "event->Initialize";
+ ev->Release();
+ hr = E_UNEXPECTED;
+ }
+ }
+
+ return hr;
+ }
+
+ // Helper function to execute a function on a script IDispatch interface.
+ HRESULT InvokeScriptFunction(const VARIANT& script_object,
+ const std::string& param) {
+ ScopedVariant script_arg(UTF8ToWide(param.c_str()).c_str());
+ return InvokeScriptFunction(script_object, script_arg.AsInput());
+ }
+
+ HRESULT InvokeScriptFunction(const VARIANT& script_object, VARIANT* param) {
+ return InvokeScriptFunction(script_object, param, 1);
+ }
+
+ HRESULT InvokeScriptFunction(const VARIANT& script_object, VARIANT* params,
+ int param_count) {
+ DCHECK(param_count >= 0);
+ DCHECK(params);
+
+ if (V_VT(&script_object) != VT_DISPATCH) {
+ return S_FALSE;
+ }
+
+ CComPtr<IDispatch> script(script_object.pdispVal);
+ HRESULT hr = script.InvokeN(static_cast<DISPID>(DISPID_VALUE),
+ params,
+ param_count);
+ // 0x80020101 == SCRIPT_E_REPORTED.
+ // When the script we're invoking has an error, we get this error back.
+ DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101) << "Failed to invoke script";
+ return hr;
+ }
+
// Gives the browser a chance to handle an accelerator that was
// sent to the out of proc chromium instance.
// Returns S_OK iff the accelerator was handled by the browser.
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
index 8dbf795..7f4e218 100644
--- a/chrome_frame/chrome_frame_automation.cc
+++ b/chrome_frame/chrome_frame_automation.cc
@@ -75,6 +75,7 @@ class ChromeFrameAutomationProxyImpl::CFMsgDispatcher
case AutomationMsg_ConnectExternalTab::ID:
InvokeCallback<Tuple3<HWND, HWND, int> >(msg, origin);
break;
+ case AutomationMsg_NavigateExternalTabAtIndex::ID:
case AutomationMsg_NavigateInExternalTab::ID:
InvokeCallback<Tuple1<AutomationMsg_NavigationResponseValues> >(msg,
origin);
@@ -144,7 +145,6 @@ struct LaunchTimeStats {
#endif
};
-
ProxyFactory::ProxyCacheEntry::ProxyCacheEntry(const std::wstring& profile)
: proxy(NULL), profile_name(profile), ref_count(1),
launch_result(AutomationLaunchResult(-1)) {
@@ -885,7 +885,6 @@ void ChromeFrameAutomationClient::SetParentWindow(HWND parent_window) {
}
if (!SetParent(parent_window)) {
- NOTREACHED();
DLOG(WARNING) << "Failed to set parent window for automation window. "
<< "Error = "
<< GetLastError();
diff --git a/chrome_frame/extra_system_apis.h b/chrome_frame/extra_system_apis.h
index 0fbe0ea..2d78d59 100644
--- a/chrome_frame/extra_system_apis.h
+++ b/chrome_frame/extra_system_apis.h
@@ -15,7 +15,7 @@
class __declspec(uuid("54A8F188-9EBD-4795-AD16-9B4945119636"))
IWebBrowserEventsService : public IUnknown {
public:
- STDMETHOD(FireBeforeNavigate2Event)(VARIANT_BOOL *cancel) = 0;
+ STDMETHOD(FireBeforeNavigate2Event)(VARIANT_BOOL* cancel) = 0;
STDMETHOD(FireNavigateComplete2Event)(VOID) = 0;
STDMETHOD(FireDownloadBeginEvent)(VOID) = 0;
STDMETHOD(FireDownloadCompleteEvent)(VOID) = 0;
@@ -31,7 +31,31 @@ IWebBrowserEventsService : public IUnknown {
class __declspec(uuid("{87CC5D04-EAFA-4833-9820-8F986530CC00}"))
IWebBrowserEventsUrlService : public IUnknown {
public:
- STDMETHOD(GetUrlForEvents)(BSTR *url) = 0;
+ STDMETHOD(GetUrlForEvents)(BSTR* url) = 0;
+};
+
+// This interface is used to call FireBeforeNavigate with additional
+// information like url. Available on IE7 onwards.
+//
+// MSDN documents this interface see:
+// http://msdn.microsoft.com/en-us/library/aa770053(VS.85).aspx)
+// but this is not included in any Platform SDK header file.
+interface __declspec(uuid("3050f801-98b5-11cf-bb82-00aa00bdce0b"))
+IDocObjectService : public IUnknown {
+ STDMETHOD(FireBeforeNavigate2)(IDispatch* dispatch,
+ LPCTSTR url, DWORD flags, LPCTSTR frame_name, BYTE* post_data,
+ DWORD post_data_len, LPCTSTR headers, BOOL play_nav_sound,
+ BOOL* cancel) = 0;
+ STDMETHOD(FireNavigateComplete2)(IHTMLWindow2* html_window2,
+ DWORD flags) = 0;
+ STDMETHOD(FireDownloadBegin)() = 0;
+ STDMETHOD(FireDownloadComplete)() = 0;
+ STDMETHOD(FireDocumentComplete)(IHTMLWindow2* html_window2, DWORD flags) = 0;
+ STDMETHOD(UpdateDesktopComponent)(IHTMLWindow2* html_window2) = 0;
+ STDMETHOD(GetPendingUrl)(BSTR* pending_url) = 0;
+ STDMETHOD(ActiveElementChanged)(IHTMLElement* html_element) = 0;
+ STDMETHOD(GetUrlSearchComponent)(BSTR* search) = 0;
+ STDMETHOD(IsErrorUrl)(LPCTSTR url, BOOL* is_error) = 0;
};
#endif // CHROME_FRAME_EXTRA_SYSTEM_APIS_H_
diff --git a/chrome_frame/html_private_window_impl.h b/chrome_frame/html_private_window_impl.h
new file mode 100644
index 0000000..358df46
--- /dev/null
+++ b/chrome_frame/html_private_window_impl.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_FRAME_HTML_PRIVATE_WINDOW_IMPL_H_
+#define CHROME_FRAME_HTML_PRIVATE_WINDOW_IMPL_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <mshtml.h>
+
+#include "chrome_tab.h" // NOLINT
+#include "chrome_frame/resource.h"
+#include "grit/chrome_frame_resources.h"
+
+interface __declspec(uuid("3050F6DC-98B5-11CF-BB82-00AA00BDCE0B"))
+IHTMLPrivateWindow : public IUnknown {
+ STDMETHOD(SuperNavigate)(BSTR , BSTR, BSTR, BSTR , VARIANT*,
+ VARIANT*, ULONG) = 0;
+ STDMETHOD(GetPendingUrl)(BSTR*) = 0;
+ STDMETHOD(SetPICSTarget)(IOleCommandTarget*) = 0;
+ STDMETHOD(PICSComplete)(int) = 0;
+ STDMETHOD(FindWindowByName)(PCWSTR, IHTMLWindow2**) = 0;
+ STDMETHOD(GetAddressBarUrl)(BSTR* url) = 0;
+};
+
+template <typename T>
+class ATL_NO_VTABLE HTMLPrivateWindowImpl : public T {
+ public:
+ HTMLPrivateWindowImpl() {}
+
+ // IHTMLPrivateWindow
+ STDMETHOD(SuperNavigate)(BSTR , BSTR, BSTR, BSTR , VARIANT*,
+ VARIANT*, ULONG) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetPendingUrl)(BSTR*) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(SetPICSTarget)(IOleCommandTarget*) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(PICSComplete)(int) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(FindWindowByName)(LPCWSTR, IHTMLWindow2**) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetAddressBarUrl)(BSTR* url) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+};
+
+#endif // CHROME_FRAME_HTML_PRIVATE_WINDOW_IMPL_H_
+
diff --git a/chrome_frame/html_window_impl.h b/chrome_frame/html_window_impl.h
new file mode 100644
index 0000000..2e76b93
--- /dev/null
+++ b/chrome_frame/html_window_impl.h
@@ -0,0 +1,385 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_FRAME_HTML_WINDOW_IMPL_H_
+#define CHROME_FRAME_HTML_WINDOW_IMPL_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <mshtml.h>
+
+#include "chrome_tab.h" // NOLINT
+#include "chrome_frame/resource.h"
+#include "grit/chrome_frame_resources.h"
+
+template <typename T>
+class ATL_NO_VTABLE HTMLWindowImpl
+ : public IDispatchImpl<T> {
+ public:
+ HTMLWindowImpl() {}
+
+ // IHTMLFramesCollection2
+ STDMETHOD(item)(VARIANT* index, VARIANT* result) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_length)(long* length) {
+ DLOG(INFO) << __FUNCTION__;
+ if (!length)
+ return E_POINTER;
+
+ *length = 0;
+ return S_OK;
+ }
+
+ // IHTMLWindow2
+ STDMETHOD(get_frames)(IHTMLFramesCollection2** collection) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_defaultStatus)(BSTR status) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_defaultStatus)(BSTR* status) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_status)(BSTR status) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_status)(BSTR* status) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(setTimeout)(BSTR expression, long msec, VARIANT* language,
+ long* timer_id) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(clearTimeout)(long timer_id) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(alert)(BSTR message) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(confirm)(BSTR message, VARIANT_BOOL* confirmed) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(prompt)(BSTR message, BSTR defstr, VARIANT* textdata) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_Image)(IHTMLImageElementFactory** factory) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_location)(IHTMLLocation** location) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_history)(IOmHistory** history) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(close)() {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_opener)(VARIANT opener) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_opener)(VARIANT* opener) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_navigator)(IOmNavigator** navigator) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_name)(BSTR name) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_name)(BSTR* name) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_parent)(IHTMLWindow2** parent) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(open)(BSTR url, BSTR name, BSTR features, VARIANT_BOOL replace,
+ IHTMLWindow2** window_result) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_self)(IHTMLWindow2** self) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_top)(IHTMLWindow2** top) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_window)(IHTMLWindow2** window) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(navigate)(BSTR url) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_onfocus)(VARIANT focus_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_onfocus)(VARIANT* focus_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_onblur)(VARIANT blur_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_onblur)(VARIANT* blur_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_onload)(VARIANT onload_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_onload)(VARIANT* onload_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_onbeforeunload)(VARIANT before_onload) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_onbeforeunload)(VARIANT* before_onload) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_onunload)(VARIANT unload_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_onunload)(VARIANT* unload_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_onhelp)(VARIANT help_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_onhelp)(VARIANT* help_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_onerror)(VARIANT error_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_onerror)(VARIANT* error_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_onresize)(VARIANT resize_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_onresize)(VARIANT* resize_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_onscroll)(VARIANT scroll_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_onscroll)(VARIANT* scroll_handler) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_document)(IHTMLDocument2** document) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_event)(IHTMLEventObj** event_object) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get__newEnum)(IUnknown** new_enum) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(showModalDialog)(BSTR dialog, VARIANT* in, VARIANT* options,
+ VARIANT* out) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(showHelp)(BSTR help_url, VARIANT help_arg, BSTR features) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_screen)(IHTMLScreen** screen) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_Option)(IHTMLOptionElementFactory** option_factory) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(focus)() {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_closed)(VARIANT_BOOL* is_closed) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(blur)() {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(scroll)(long x, long y) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_clientInformation)(IOmNavigator** navigator) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(setInterval)(BSTR expression, long msec, VARIANT* language,
+ long* timerID) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(clearInterval)(long timerID) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(put_offscreenBuffering)(VARIANT off_screen_buffering) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_offscreenBuffering)(VARIANT* off_screen_buffering) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(execScript)(BSTR code, BSTR language, VARIANT* ret) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(toString)(BSTR* String) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(scrollBy)(long x, long y) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(scrollTo)(long x, long y) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(moveTo)(long x, long y) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(moveBy)(long x, long y) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(resizeTo)(long x, long y) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(resizeBy)(long x, long y) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(get_external)(IDispatch** external) {
+ DLOG(INFO) << __FUNCTION__;
+ return E_NOTIMPL;
+ }
+
+};
+
+#endif // CHROME_FRAME_HTML_WINDOW_IMPL_H_
+
diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc
index 54d18de..cb59615 100644
--- a/chrome_frame/test/chrome_frame_test_utils.cc
+++ b/chrome_frame/test/chrome_frame_test_utils.cc
@@ -421,7 +421,7 @@ int CloseAllIEWindows() {
return ret;
}
-void ShowChromeFrameContextMenuTask() {
+void ShowChromeFrameContextMenu() {
static const int kChromeFrameContextMenuTimeout = 500;
HWND renderer_window = GetChromeRendererWindow();
EXPECT_TRUE(IsWindow(renderer_window));
@@ -438,15 +438,6 @@ void ShowChromeFrameContextMenuTask() {
kChromeFrameContextMenuTimeout);
}
-void ShowChromeFrameContextMenu() {
- static const int kContextMenuDelay = 5000;
-
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- NewRunnableFunction(ShowChromeFrameContextMenuTask),
- kContextMenuDelay);
-}
-
void SetKeyboardFocusToWindow(HWND window, int x, int y) {
if (!IsTopLevelWindow(window)) {
window = GetAncestor(window, GA_ROOT);
diff --git a/chrome_frame/test/chrome_frame_unittests.cc b/chrome_frame/test/chrome_frame_unittests.cc
index d43cd52..875695e 100644
--- a/chrome_frame/test/chrome_frame_unittests.cc
+++ b/chrome_frame/test/chrome_frame_unittests.cc
@@ -24,10 +24,12 @@
#include "chrome_frame/crash_reporting/vectored_handler-impl.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
#include "chrome_frame/test_utils.h"
-#include "chrome_frame/utils.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/helper.h"
+
+#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
#include "testing/gmock_mutant.h"
+
using testing::CreateFunctor;
const wchar_t kDocRoot[] = L"chrome_frame\\test\\data";
@@ -73,6 +75,8 @@ _ATL_FUNC_INFO WebBrowserEventSink::kNewWindow3Info = {
}
};
+_ATL_FUNC_INFO WebBrowserEventSink::kVoidMethodInfo = {
+ CC_STDCALL, VT_EMPTY, 0, {NULL}};
void ChromeFrameTestWithWebServer::SetUp() {
server_.SetUp();
@@ -1334,8 +1338,45 @@ HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser) {
}
// WebBrowserEventSink member defines
+STDMETHODIMP WebBrowserEventSink::OnBeforeNavigate2Internal(
+ IDispatch* dispatch, VARIANT* url, VARIANT* flags,
+ VARIANT* target_frame_name, VARIANT* post_data, VARIANT* headers,
+ VARIANT_BOOL* cancel) {
+ DLOG(INFO) << __FUNCTION__;
+ // Reset any existing reference to chrome frame since this is a new
+ // navigation.
+ chrome_frame_ = NULL;
+ return OnBeforeNavigate2(dispatch, url, flags, target_frame_name,
+ post_data, headers, cancel);
+}
+
+STDMETHODIMP_(void) WebBrowserEventSink::OnNavigateComplete2Internal(
+ IDispatch* dispatch, VARIANT* url) {
+ DLOG(INFO) << __FUNCTION__;
+ ConnectToChromeFrame();
+ OnNavigateComplete2(dispatch, url);
+}
+
+HRESULT WebBrowserEventSink::OnLoadInternal(const VARIANT* param) {
+ DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal;
+ OnLoad(param->bstrVal);
+ return S_OK;
+}
+
+HRESULT WebBrowserEventSink::OnLoadErrorInternal(const VARIANT* param) {
+ DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal;
+ OnLoadError(param->bstrVal);
+ return S_OK;
+}
+
+HRESULT WebBrowserEventSink::OnMessageInternal(const VARIANT* param) {
+ DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal;
+ OnMessage(param->bstrVal);
+ return S_OK;
+}
+
HRESULT WebBrowserEventSink::LaunchIEAndNavigate(
- const std::wstring& navigate_url, _IDispEvent* sink) {
+ const std::wstring& navigate_url) {
int major_version = 0;
int minor_version = 0;
int bugfix_version = 0;
@@ -1351,19 +1392,47 @@ HRESULT WebBrowserEventSink::LaunchIEAndNavigate(
EXPECT_TRUE(S_OK == LaunchIEAsComServer(web_browser2_.Receive()));
web_browser2_->put_Visible(VARIANT_TRUE);
- HRESULT hr = sink->DispEventAdvise(web_browser2_,
- &DIID_DWebBrowserEvents2);
+ HRESULT hr = DispEventAdvise(web_browser2_, &DIID_DWebBrowserEvents2);
EXPECT_TRUE(hr == S_OK);
+ return Navigate(navigate_url);
+}
+HRESULT WebBrowserEventSink::Navigate(const std::wstring& navigate_url) {
VARIANT empty = ScopedVariant::kEmptyVariant;
ScopedVariant url;
url.Set(navigate_url.c_str());
+ HRESULT hr = S_OK;
hr = web_browser2_->Navigate2(url.AsInput(), &empty, &empty, &empty, &empty);
EXPECT_TRUE(hr == S_OK);
return hr;
}
+void WebBrowserEventSink::ConnectToChromeFrame() {
+ DCHECK(web_browser2_);
+ ScopedComPtr<IShellBrowser> shell_browser;
+ DoQueryService(SID_STopLevelBrowser, web_browser2_,
+ shell_browser.Receive());
+
+ if (shell_browser) {
+ ScopedComPtr<IShellView> shell_view;
+ shell_browser->QueryActiveShellView(shell_view.Receive());
+ if (shell_view) {
+ shell_view->GetItemObject(SVGIO_BACKGROUND, __uuidof(IChromeFrame),
+ reinterpret_cast<void**>(chrome_frame_.Receive()));
+ }
+
+ if (chrome_frame_) {
+ ScopedVariant onmessage(onmessage_.ToDispatch());
+ ScopedVariant onloaderror(onloaderror_.ToDispatch());
+ ScopedVariant onload(onload_.ToDispatch());
+ EXPECT_HRESULT_SUCCEEDED(chrome_frame_->put_onmessage(onmessage));
+ EXPECT_HRESULT_SUCCEEDED(chrome_frame_->put_onloaderror(onloaderror));
+ EXPECT_HRESULT_SUCCEEDED(chrome_frame_->put_onload(onload));
+ }
+ }
+}
+
const int kChromeFrameLaunchDelay = 5;
const int kChromeFrameLongNavigationTimeoutInSeconds = 10;
@@ -1402,6 +1471,10 @@ class MockWebBrowserEventSink : public WebBrowserEventSink {
VARIANT* frame_name,
VARIANT* status_code,
VARIANT* cancel));
+
+ MOCK_METHOD1(OnLoad, void (const wchar_t* url)); // NOLINT
+ MOCK_METHOD1(OnLoadError, void (const wchar_t* url)); // NOLINT
+ MOCK_METHOD1(OnMessage, void (const wchar_t* message)); // NOLINT
};
using testing::_;
@@ -1431,7 +1504,7 @@ TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) {
QUIT_LOOP(loop),
testing::Return(S_OK)));
- HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFileUrl, &mock);
+ HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFileUrl);
ASSERT_HRESULT_SUCCEEDED(hr);
if (hr == S_FALSE)
return;
@@ -1455,29 +1528,34 @@ const wchar_t kChromeFrameFullTabWindowOpenPopupUrl[] =
// window.open target page is supposed to render within Chrome.
TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_WindowOpen) {
TimedMsgLoop loop;
-
CComObjectStackEx<MockWebBrowserEventSink> mock;
+ ::testing::InSequence sequence;
EXPECT_CALL(mock,
OnBeforeNavigate2(
_, testing::Field(&VARIANT::bstrVal,
testing::StrCaseEq(kChromeFrameFullTabWindowOpenTestUrl)),
_, _, _, _, _))
- .Times(1)
.WillOnce(testing::Return(S_OK));
+ EXPECT_CALL(mock, OnNavigateComplete2(_, _))
+ .WillOnce(testing::Return());
+ EXPECT_CALL(mock,
+ OnLoad(testing::StrEq(kChromeFrameFullTabWindowOpenTestUrl)))
+ .WillOnce(testing::Return());
EXPECT_CALL(mock,
OnBeforeNavigate2(
_, testing::Field(&VARIANT::bstrVal,
testing::StrCaseEq(kChromeFrameFullTabWindowOpenPopupUrl)),
_, _, _, _, _))
- .Times(1)
- .WillOnce(testing::DoAll(
- QUIT_LOOP_SOON(loop, 2),
- testing::Return(S_OK)));
+ .WillOnce(testing::Return(S_OK));
+ EXPECT_CALL(mock, OnNavigateComplete2(_, _))
+ .WillOnce(testing::Return());
+ EXPECT_CALL(mock,
+ OnLoad(testing::StrEq(kChromeFrameFullTabWindowOpenPopupUrl)))
+ .WillOnce(QUIT_LOOP_SOON(loop, 2));
- HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFullTabWindowOpenTestUrl,
- &mock);
+ HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFullTabWindowOpenTestUrl);
ASSERT_HRESULT_SUCCEEDED(hr);
if (hr == S_FALSE)
return;
@@ -1492,8 +1570,8 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_WindowOpen) {
chrome_frame_test::CloseAllIEWindows();
}
-const wchar_t kChromeFrameAboutBlankUrl[] =
- L"cf:about:blank";
+const wchar_t kSubFrameUrl1[] =
+ L"http://localhost:1337/files/sub_frame1.html";
const wchar_t kChromeFrameAboutVersion[] =
L"cf:about:version";
@@ -1510,18 +1588,17 @@ const wchar_t kChromeFrameAboutVersion[] =
// http://code.google.com/p/chromium/issues/detail?id=26549
TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_AboutChromeFrame) {
TimedMsgLoop loop;
-
CComObjectStackEx<MockWebBrowserEventSink> mock;
EXPECT_CALL(mock,
OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
- testing::StrCaseEq(kChromeFrameAboutBlankUrl)),
+ testing::StrCaseEq(kSubFrameUrl1)),
_, _, _, _, _))
.Times(1)
.WillOnce(testing::Return(S_OK));
-
EXPECT_CALL(mock, OnNavigateComplete2(_, _))
- .Times(1)
+ .WillOnce(testing::Return());
+ EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1)))
.WillOnce(testing::InvokeWithoutArgs(
&chrome_frame_test::ShowChromeFrameContextMenu));
@@ -1531,7 +1608,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_AboutChromeFrame) {
.Times(1)
.WillOnce(QUIT_LOOP(loop));
- HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameAboutBlankUrl, &mock);
+ HRESULT hr = mock.LaunchIEAndNavigate(kSubFrameUrl1);
ASSERT_HRESULT_SUCCEEDED(hr);
if (hr == S_FALSE)
return;
@@ -1565,3 +1642,102 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_ChromeFrameKeyboardTest) {
ASSERT_TRUE(CheckResultFile(L"FullTab_KeyboardTest", "OK"));
}
+const wchar_t kSubFrameUrl2[] =
+ L"http://localhost:1337/files/sub_frame2.html";
+const wchar_t kSubFrameUrl3[] =
+ L"http://localhost:1337/files/sub_frame3.html";
+
+// Hack to pass a reference to the argument instead of value. Passing by
+// value evaluates the argument at the mock specification time which is
+// not always ideal. For e.g. At the time of mock creation, web_browser2_
+// pointer is not set up yet so by passing a reference to it instead of
+// a value we allow it to be created later.
+template <typename T> T** ReceivePointer(scoped_refptr<T>& p) { // NOLINT
+ return reinterpret_cast<T**>(&p);
+}
+
+// Full tab mode back/forward test
+// Launch and navigate chrome frame to a set of URLs and test back forward
+TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) {
+ TimedMsgLoop loop;
+ CComObjectStackEx<MockWebBrowserEventSink> mock;
+ ::testing::InSequence sequence; // Everything in sequence
+
+ // Navigate to url 2 after the previous navigation is complete
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
+ testing::StrCaseEq(kSubFrameUrl1)),
+ _, _, _, _, _))
+ .WillOnce(testing::Return(S_OK));
+ EXPECT_CALL(mock, OnNavigateComplete2(_, _))
+ .WillOnce(testing::Return());
+ EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1)))
+ .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(
+ CreateFunctor(&mock, &WebBrowserEventSink::Navigate,
+ std::wstring(kSubFrameUrl2)))));
+
+ // Navigate to url 3 after the previous navigation is complete
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
+ testing::StrCaseEq(kSubFrameUrl2)),
+ _, _, _, _, _))
+ .WillOnce(testing::Return(S_OK));
+ EXPECT_CALL(mock, OnNavigateComplete2(_, _))
+ .WillOnce(testing::Return());
+ EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl2)))
+ .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(
+ CreateFunctor(&mock, &WebBrowserEventSink::Navigate,
+ std::wstring(kSubFrameUrl3)))));
+
+ // We have reached url 3 and have two back entries for url 1 & 2
+ // Go back to url 2 now
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
+ testing::StrCaseEq(kSubFrameUrl3)),
+ _, _, _, _, _))
+ .WillOnce(testing::Return(S_OK));
+ EXPECT_CALL(mock, OnNavigateComplete2(_, _))
+ .WillOnce(testing::Return());
+ EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl3)))
+ .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(
+ CreateFunctor(ReceivePointer(mock.web_browser2_),
+ &IWebBrowser::GoBack))));
+
+ // We have reached url 2 and have 1 back & 1 forward entries for url 1 & 3
+ // Go back to url 1 now
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
+ testing::StrCaseEq(kSubFrameUrl2)),
+ _, _, _, _, _))
+ .WillOnce(testing::Return(S_OK));
+ EXPECT_CALL(mock, OnNavigateComplete2(_, _))
+ .WillOnce(testing::Return());
+ EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl2)))
+ .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(
+ CreateFunctor(ReceivePointer(mock.web_browser2_),
+ &IWebBrowser::GoBack))));
+
+ // We have reached url 1 and have 0 back & 2 forward entries for url 2 & 3
+ // Go back to url 1 now
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
+ testing::StrCaseEq(kSubFrameUrl1)),
+ _, _, _, _, _));
+ EXPECT_CALL(mock, OnNavigateComplete2(_, _))
+ .WillOnce(testing::Return());
+ EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1)))
+ .WillOnce(QUIT_LOOP_SOON(loop, 2));
+
+ HRESULT hr = mock.LaunchIEAndNavigate(kSubFrameUrl1);
+ ASSERT_HRESULT_SUCCEEDED(hr);
+ if (hr == S_FALSE)
+ return;
+
+ ASSERT_TRUE(mock.web_browser2() != NULL);
+
+ loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
+
+ mock.Uninitialize();
+ chrome_frame_test::CloseAllIEWindows();
+}
+
diff --git a/chrome_frame/test/chrome_frame_unittests.h b/chrome_frame/test/chrome_frame_unittests.h
index 9dcaadc..7ecdf50 100644
--- a/chrome_frame/test/chrome_frame_unittests.h
+++ b/chrome_frame/test/chrome_frame_unittests.h
@@ -9,14 +9,24 @@
#include <string>
#include <exdisp.h>
#include <exdispid.h>
+#include <mshtml.h>
+#include <shlguid.h>
+#include <shobjidl.h>
+#include "base/compiler_specific.h"
#include "base/ref_counted.h"
#include "base/scoped_comptr_win.h"
+#include "base/scoped_variant_win.h"
#include "base/scoped_handle_win.h"
#include "googleurl/src/gurl.h"
#include "chrome_frame/test/http_server.h"
+#include "chrome_frame/test_utils.h"
+#include "chrome_frame/utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+// Include without path to make GYP build see it.
+#include "chrome_tab.h" // NOLINT
+
// Class that:
// 1) Starts the local webserver,
// 2) Supports launching browsers - Internet Explorer and Firefox with local url
@@ -105,35 +115,50 @@ class WebBrowserEventSink
public:
typedef IDispEventSimpleImpl<0, WebBrowserEventSink,
&DIID_DWebBrowserEvents2> DispEventsImpl;
- WebBrowserEventSink() {}
+ WebBrowserEventSink()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(
+ onmessage_(this, &WebBrowserEventSink::OnMessageInternal)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ onloaderror_(this, &WebBrowserEventSink::OnLoadErrorInternal)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ onload_(this, &WebBrowserEventSink::OnLoadInternal)) {
+ }
+
~WebBrowserEventSink() {
Uninitialize();
}
void Uninitialize() {
+ chrome_frame_ = NULL;
if (web_browser2_.get()) {
DispEventUnadvise(web_browser2_);
+ web_browser2_->Quit();
web_browser2_.Release();
+ // Give IE some time to quit and release our references
+ Sleep(1000);
}
}
// Helper function to launch IE and navigate to a URL.
// Returns S_OK on success, S_FALSE if the test was not run, other
// errors on failure.
- HRESULT LaunchIEAndNavigate(const std::wstring& navigate_url,
- _IDispEvent* sink);
+ HRESULT LaunchIEAndNavigate(const std::wstring& navigate_url);
+
+ HRESULT Navigate(const std::wstring& navigate_url);
BEGIN_COM_MAP(WebBrowserEventSink)
END_COM_MAP()
BEGIN_SINK_MAP(WebBrowserEventSink)
- SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2,
- OnBeforeNavigate2, &kBeforeNavigate2Info)
- SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2,
- OnNavigateComplete2, &kNavigateComplete2Info)
- SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR,
+ SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2,
+ OnBeforeNavigate2Internal, &kBeforeNavigate2Info)
+ SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN,
+ OnDownloadBegin, &kVoidMethodInfo)
+ SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2,
+ OnNavigateComplete2Internal, &kNavigateComplete2Info)
+ SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR,
OnNavigateError, &kNavigateErrorInfo)
- SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW3,
+ SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW3,
OnNewWindow3, &kNewWindow3Info)
END_SINK_MAP()
@@ -147,18 +172,20 @@ END_SINK_MAP()
flags, VARIANT* target_frame_name,
VARIANT* post_data, VARIANT* headers,
VARIANT_BOOL* cancel) {
- DLOG(INFO) << __FUNCTION__;
return S_OK;
}
- STDMETHOD_(void, OnNavigateComplete2)(IDispatch* dispatch, VARIANT* url) {
- DLOG(INFO) << __FUNCTION__;
- }
-
+ STDMETHOD(OnBeforeNavigate2Internal)(IDispatch* dispatch, VARIANT* url,
+ VARIANT* flags,
+ VARIANT* target_frame_name,
+ VARIANT* post_data, VARIANT* headers,
+ VARIANT_BOOL* cancel);
+ STDMETHOD_(void, OnDownloadBegin)() {}
+ STDMETHOD_(void, OnNavigateComplete2Internal)(IDispatch* dispatch,
+ VARIANT* url);
+ STDMETHOD_(void, OnNavigateComplete2)(IDispatch* dispatch, VARIANT* url) {}
STDMETHOD_(void, OnNewWindow3)(IDispatch** dispatch, VARIANT_BOOL* Cancel,
- DWORD flags, BSTR url_context, BSTR url) {
- DLOG(INFO) << __FUNCTION__;
- }
+ DWORD flags, BSTR url_context, BSTR url) {}
#ifdef _DEBUG
STDMETHOD(Invoke)(DISPID dispid, REFIID riid,
@@ -170,16 +197,36 @@ END_SINK_MAP()
}
#endif // _DEBUG
+ // Chrome frame callbacks
+ virtual void OnLoad(const wchar_t* url) {}
+ virtual void OnLoadError(const wchar_t* url) {}
+ virtual void OnMessage(const wchar_t* message) {}
+
IWebBrowser2* web_browser2() {
return web_browser2_.get();
}
protected:
+ // IChromeFrame callbacks
+ HRESULT OnLoadInternal(const VARIANT* param);
+ HRESULT OnLoadErrorInternal(const VARIANT* param);
+ HRESULT OnMessageInternal(const VARIANT* param);
+
+ void ConnectToChromeFrame();
+
+ public:
+ ScopedComPtr<IWebBrowser2> web_browser2_;
+ ScopedComPtr<IChromeFrame> chrome_frame_;
+ DispCallback<WebBrowserEventSink> onmessage_;
+ DispCallback<WebBrowserEventSink> onloaderror_;
+ DispCallback<WebBrowserEventSink> onload_;
+
+ protected:
static _ATL_FUNC_INFO kBeforeNavigate2Info;
static _ATL_FUNC_INFO kNavigateComplete2Info;
static _ATL_FUNC_INFO kNavigateErrorInfo;
static _ATL_FUNC_INFO kNewWindow3Info;
- ScopedComPtr<IWebBrowser2> web_browser2_;
+ static _ATL_FUNC_INFO kVoidMethodInfo;
};
#endif // CHROME_FRAME_TEST_CHROME_FRAME_UNITTESTS_H_
diff --git a/chrome_frame/test/data/anchor.html b/chrome_frame/test/data/anchor.html
new file mode 100644
index 0000000..2687982
--- /dev/null
+++ b/chrome_frame/test/data/anchor.html
@@ -0,0 +1,51 @@
+<HTML>
+ <HEAD>
+ <meta http-equiv="X-UA-Compatible" content="chrome=1" />
+ <TITLE> Chrome Frame Test </TITLE>
+ </HEAD>
+ <BODY>
+ Chrome trame in tab mode
+
+ Jump to different named sections here
+ <a href="#a1">Jump to A1</a>
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <a name="a1"> A1 </a>
+ <a href="#a2">Jump to A2</a>
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <a name="a2"> A2 </a>
+ <a href="#a3">Jump to A3</a>
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <a name="a3"> A3 </a>
+ <a href="#a4">Jump to A4</a>
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <a name="a4"> A4 </a>
+ </BODY>
+</HTML>
diff --git a/chrome_frame/test/data/frame_test.html b/chrome_frame/test/data/frame_test.html
new file mode 100644
index 0000000..fc6e6f9
--- /dev/null
+++ b/chrome_frame/test/data/frame_test.html
@@ -0,0 +1,18 @@
+<html>
+ <head>
+ <meta http-equiv="x-ua-compatible" content="chrome=1" />
+ </head>
+ <body>
+ <p> Frames </p>
+ Test of sub frame navigation
+ <P> <A href="sub_frame1.html" target="x">Frame 1</A> </p>
+ <P> <A href="sub_frame2.html" target="x">Frame 2</A> </p>
+ <P> <A href="sub_frame3.html" target="x">Frame 3</A> </p>
+ <P> <A href="sub_frame4.html" target="x">Frame 4</A> </p>
+ <br>
+ <br>
+ <iframe src ="about:blank" name="x" width="400" height="200">
+ </iframe>
+
+ </body>
+</html>
diff --git a/chrome_frame/test/data/sub_frame1.html b/chrome_frame/test/data/sub_frame1.html
new file mode 100644
index 0000000..90ee623
--- /dev/null
+++ b/chrome_frame/test/data/sub_frame1.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <meta http-equiv="x-ua-compatible" content="chrome=1" />
+ <title>Sub frame 1</title>
+ </head>
+ <body>
+ Sub frame 1
+ <br/><br/>
+ <br>
+ <div id="statusPanel" style="border: 1px solid red; width: 100%">
+ LOG:
+ </div>
+ </body>
+</html>
+
diff --git a/chrome_frame/test/data/sub_frame2.html b/chrome_frame/test/data/sub_frame2.html
new file mode 100644
index 0000000..3075a22
--- /dev/null
+++ b/chrome_frame/test/data/sub_frame2.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <meta http-equiv="x-ua-compatible" content="chrome=1" />
+ <title>Sub frame 2</title>
+ </head>
+ <body>
+ Sub frame 2
+ <br/><br/>
+ <br>
+ <div id="statusPanel" style="border: 1px solid red; width: 100%">
+ LOG:
+ </div>
+ </body>
+</html>
+
diff --git a/chrome_frame/test/data/sub_frame3.html b/chrome_frame/test/data/sub_frame3.html
new file mode 100644
index 0000000..279d38f
--- /dev/null
+++ b/chrome_frame/test/data/sub_frame3.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <meta http-equiv="x-ua-compatible" content="chrome=1" />
+ <title>Sub frame 3</title>
+ </head>
+ <body>
+ Sub frame 3
+ <br/><br/>
+ <br>
+ <div id="statusPanel" style="border: 1px solid red; width: 100%">
+ LOG:
+ </div>
+ </body>
+</html>
+
diff --git a/chrome_frame/test/data/sub_frame4.html b/chrome_frame/test/data/sub_frame4.html
new file mode 100644
index 0000000..f50eba2
--- /dev/null
+++ b/chrome_frame/test/data/sub_frame4.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <meta http-equiv="x-ua-compatible" content="chrome=1" />
+ <title>Sub frame 4</title>
+ </head>
+ <body>
+ Sub frame 4
+ <br/><br/>
+ <br>
+ <div id="statusPanel" style="border: 1px solid red; width: 100%">
+ LOG:
+ </div>
+ </body>
+</html>
+
diff --git a/chrome_frame/test/perf/chrome_frame_perftest.cc b/chrome_frame/test/perf/chrome_frame_perftest.cc
index d93ebd5..762b424 100644
--- a/chrome_frame/test/perf/chrome_frame_perftest.cc
+++ b/chrome_frame/test/perf/chrome_frame_perftest.cc
@@ -17,6 +17,7 @@
#include "base/scoped_ptr.h"
#include "base/scoped_bstr_win.h"
#include "base/scoped_comptr_win.h"
+#include "base/scoped_variant_win.h"
#include "base/string_util.h"
#include "base/time.h"
#include "chrome/common/chrome_constants.h"
@@ -37,41 +38,6 @@ const wchar_t kFlashControlKey[] =
using base::TimeDelta;
using base::TimeTicks;
-// Callback description for onload, onloaderror, onmessage
-static _ATL_FUNC_INFO g_single_param = {CC_STDCALL, VT_EMPTY, 1, {VT_VARIANT}};
-// Simple class that forwards the callbacks.
-template <typename T>
-class DispCallback
- : public IDispEventSimpleImpl<1, DispCallback<T>, &IID_IDispatch> {
- public:
- typedef HRESULT (T::*Method)(VARIANT* param);
-
- DispCallback(T* owner, Method method) : owner_(owner), method_(method) {
- }
-
- BEGIN_SINK_MAP(DispCallback)
- SINK_ENTRY_INFO(1, IID_IDispatch, DISPID_VALUE, OnCallback, &g_single_param)
- END_SINK_MAP()
-
- virtual ULONG STDMETHODCALLTYPE AddRef() {
- return owner_->AddRef();
- }
- virtual ULONG STDMETHODCALLTYPE Release() {
- return owner_->Release();
- }
-
- STDMETHOD(OnCallback)(VARIANT param) {
- return (owner_->*method_)(&param);
- }
-
- IDispatch* ToDispatch() {
- return reinterpret_cast<IDispatch*>(this);
- }
-
- T* owner_;
- Method method_;
-};
-
// This class implements an ActiveX container which hosts the ChromeFrame
// ActiveX control. It provides hooks which can be implemented by derived
// classes for implementing performance measurement, etc.
@@ -98,19 +64,19 @@ class ChromeFrameActiveXContainer
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
END_MSG_MAP()
- HRESULT OnMessageCallback(VARIANT* param) {
+ HRESULT OnMessageCallback(const VARIANT* param) {
DLOG(INFO) << __FUNCTION__;
OnMessageCallbackImpl(param);
return S_OK;
}
- HRESULT OnLoadErrorCallback(VARIANT* param) {
+ HRESULT OnLoadErrorCallback(const VARIANT* param) {
DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal;
OnLoadErrorCallbackImpl(param);
return S_OK;
}
- HRESULT OnLoadCallback(VARIANT* param) {
+ HRESULT OnLoadCallback(const VARIANT* param) {
DLOG(INFO) << __FUNCTION__ << " " << param->bstrVal;
OnLoadCallbackImpl(param);
return S_OK;
@@ -210,9 +176,9 @@ class ChromeFrameActiveXContainer
&prop_notify_cookie_);
DCHECK(hr == S_OK) << "AtlAdvice for IPropertyNotifySink failed " << hr;
- CComVariant onmessage(onmsg_.ToDispatch());
- CComVariant onloaderror(onloaderror_.ToDispatch());
- CComVariant onload(onload_.ToDispatch());
+ ScopedVariant onmessage(onmsg_.ToDispatch());
+ ScopedVariant onloaderror(onloaderror_.ToDispatch());
+ ScopedVariant onload(onload_.ToDispatch());
EXPECT_HRESULT_SUCCEEDED(tab_->put_onmessage(onmessage));
EXPECT_HRESULT_SUCCEEDED(tab_->put_onloaderror(onloaderror));
EXPECT_HRESULT_SUCCEEDED(tab_->put_onload(onload));
@@ -224,13 +190,13 @@ class ChromeFrameActiveXContainer
virtual void OnReadyStateChanged(long ready_state) {}
virtual void OnRequestEditImpl(DISPID disp_id) {}
- virtual void OnMessageCallbackImpl(VARIANT* param) {}
+ virtual void OnMessageCallbackImpl(const VARIANT* param) {}
- virtual void OnLoadCallbackImpl(VARIANT* param) {
+ virtual void OnLoadCallbackImpl(const VARIANT* param) {
PostMessage(WM_CLOSE);
}
- virtual void OnLoadErrorCallbackImpl(VARIANT* param) {
+ virtual void OnLoadErrorCallbackImpl(const VARIANT* param) {
PostMessage(WM_CLOSE);
}
virtual void BeforeNavigateImpl(const char* url) {}
@@ -281,12 +247,12 @@ class ChromeFrameActiveXContainerPerf : public ChromeFrameActiveXContainer {
}
}
- virtual void OnLoadCallbackImpl(VARIANT* param) {
+ virtual void OnLoadCallbackImpl(const VARIANT* param) {
PostMessage(WM_CLOSE);
perf_navigate_->Done();
}
- virtual void OnLoadErrorCallbackImpl(VARIANT* param) {
+ virtual void OnLoadErrorCallbackImpl(const VARIANT* param) {
PostMessage(WM_CLOSE);
perf_navigate_->Done();
}
@@ -591,7 +557,7 @@ class ChromeFrameMemoryTest : public ChromeFramePerfTestBase {
StartTest(url, test_name);
}
- void OnNavigationSuccess(VARIANT* param) {
+ void OnNavigationSuccess(const VARIANT* param) {
ASSERT_TRUE(param != NULL);
ASSERT_EQ(VT_BSTR, param->vt);
@@ -599,7 +565,7 @@ class ChromeFrameMemoryTest : public ChromeFramePerfTestBase {
InitiateNextNavigation();
}
- void OnNavigationFailure(VARIANT* param) {
+ void OnNavigationFailure(const VARIANT* param) {
ASSERT_TRUE(param != NULL);
ASSERT_EQ(VT_BSTR, param->vt);
@@ -809,11 +775,11 @@ class ChromeFrameActiveXContainerMemory : public ChromeFrameActiveXContainer {
}
protected:
- virtual void OnLoadCallbackImpl(VARIANT* param) {
+ virtual void OnLoadCallbackImpl(const VARIANT* param) {
delegate_->OnNavigationSuccess(param);
}
- virtual void OnLoadErrorCallbackImpl(VARIANT* param) {
+ virtual void OnLoadErrorCallbackImpl(const VARIANT* param) {
delegate_->OnNavigationFailure(param);
}
diff --git a/chrome_frame/test_utils.h b/chrome_frame/test_utils.h
index 85f5cc5..260b4b5 100644
--- a/chrome_frame/test_utils.h
+++ b/chrome_frame/test_utils.h
@@ -7,6 +7,9 @@
#include <string>
+#include <atlbase.h>
+#include <atlcom.h>
+
#include "base/file_path.h"
// Helper class used to register different chrome frame DLLs while running
@@ -38,4 +41,40 @@ class ScopedChromeFrameRegistrar {
std::wstring original_dll_path_;
};
+// Callback description for onload, onloaderror, onmessage
+static _ATL_FUNC_INFO g_single_param = {CC_STDCALL, VT_EMPTY, 1, {VT_VARIANT}};
+// Simple class that forwards the callbacks.
+template <typename T>
+class DispCallback
+ : public IDispEventSimpleImpl<1, DispCallback<T>, &IID_IDispatch> {
+ public:
+ typedef HRESULT (T::*Method)(const VARIANT* param);
+
+ DispCallback(T* owner, Method method) : owner_(owner), method_(method) {
+ }
+
+ BEGIN_SINK_MAP(DispCallback)
+ SINK_ENTRY_INFO(1, IID_IDispatch, DISPID_VALUE, OnCallback, &g_single_param)
+ END_SINK_MAP()
+
+ virtual ULONG STDMETHODCALLTYPE AddRef() {
+ return owner_->AddRef();
+ }
+ virtual ULONG STDMETHODCALLTYPE Release() {
+ return owner_->Release();
+ }
+
+ STDMETHOD(OnCallback)(VARIANT param) {
+ return (owner_->*method_)(&param);
+ }
+
+ IDispatch* ToDispatch() {
+ return reinterpret_cast<IDispatch*>(this);
+ }
+
+ T* owner_;
+ Method method_;
+};
+
+
#endif // CHROME_FRAME_TEST_UTILS_H_