diff options
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_)(¶m); - } - - 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_)(¶m); + } + + IDispatch* ToDispatch() { + return reinterpret_cast<IDispatch*>(this); + } + + T* owner_; + Method method_; +}; + + #endif // CHROME_FRAME_TEST_UTILS_H_ |