diff options
-rw-r--r-- | chrome_frame/bho.cc | 57 | ||||
-rw-r--r-- | chrome_frame/bho.h | 23 | ||||
-rw-r--r-- | chrome_frame/test/data/host_browser.html | 8 | ||||
-rw-r--r-- | chrome_frame/test/test_mock_with_web_server.cc | 62 |
4 files changed, 140 insertions, 10 deletions
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc index e275707..5c9fc89 100644 --- a/chrome_frame/bho.cc +++ b/chrome_frame/bho.cc @@ -47,7 +47,24 @@ _ATL_FUNC_INFO Bho::kBeforeNavigate2Info = { } }; -Bho::Bho() { +_ATL_FUNC_INFO Bho::kNavigateComplete2Info = { + CC_STDCALL, VT_EMPTY, 2, { + VT_DISPATCH, + VT_VARIANT | VT_BYREF + } +}; + +_ATL_FUNC_INFO Bho::kNavigateErrorInfo = { + CC_STDCALL, VT_EMPTY, 5, { + VT_DISPATCH, + VT_VARIANT | VT_BYREF, + VT_VARIANT | VT_BYREF, + VT_VARIANT | VT_BYREF, + VT_BOOL | VT_BYREF, + } +}; + +Bho::Bho() : pending_navigation_count_(0) { } HRESULT Bho::FinalConstruct() { @@ -115,10 +132,27 @@ STDMETHODIMP Bho::BeforeNavigate2(IDispatch* dispatch, VARIANT* url, referrer_.clear(); } url_ = url->bstrVal; + pending_navigation_count_++; ProcessOptInUrls(web_browser2, url->bstrVal); return S_OK; } +STDMETHODIMP_(void) Bho::NavigateComplete2(IDispatch* dispatch, + VARIANT* url) { + DLOG(INFO) << "In NavigateComplete2 for url:" << url->bstrVal; + pending_navigation_count_--; + DCHECK(pending_navigation_count_ >= 0); +} + +STDMETHODIMP_(void) Bho::OnNavigateError(IDispatch* dispatch, VARIANT* url, + VARIANT* frame_name, + VARIANT* status_code, + VARIANT* cancel) { + DLOG(INFO) << "In NavigateError for url:" << url->bstrVal; + pending_navigation_count_--; + DCHECK(pending_navigation_count_ >= 0); +} + HRESULT Bho::NavigateToCurrentUrlInCF(IBrowserService* browser) { DCHECK(browser); MarkBrowserOnThreadForCFNavigation(browser); @@ -192,7 +226,13 @@ void ClearDocumentContents(IUnknown* browser) { // Returns true if the currently loaded document in the browser has // any embedded items such as a frame or an iframe. -bool DocumentHasEmbeddedItems(IUnknown* browser) { +bool DocumentHasEmbeddedItems(IUnknown* browser, + int pending_navigation_count) { + // For a document with embedded frames the pending navigation count will be + // greater than 1. + if (pending_navigation_count <= 1) + return false; + bool has_embedded_items = false; ScopedComPtr<IWebBrowser2> web_browser2; @@ -238,12 +278,12 @@ HRESULT Bho::OnHttpEquiv(IBrowserService_OnHttpEquiv_Fn original_httpequiv, // notification is coming from those and not the top level document. // The embedded items should only be created once the top level // doc has been created. - if (!DocumentHasEmbeddedItems(browser)) { - Bho* bho = Bho::GetCurrentThreadBhoInstance(); - DCHECK(bho); - DLOG(INFO) << "Found tag in page. Marking browser." << bho->url() << - StringPrintf(" tid=0x%08X", ::GetCurrentThreadId()); - if (bho) { + Bho* bho = Bho::GetCurrentThreadBhoInstance(); + DCHECK(bho); + if (bho) { + if (!DocumentHasEmbeddedItems(browser, bho->pending_navigation_count())) { + DLOG(INFO) << "Found tag in page. Marking browser." << bho->url() << + StringPrintf(" tid=0x%08X", ::GetCurrentThreadId()); // TODO(tommi): See if we can't figure out a cleaner way to avoid // this. For some documents we can hit a problem here. When we // attempt to navigate the document again in CF, mshtml can "complete" @@ -258,7 +298,6 @@ HRESULT Bho::OnHttpEquiv(IBrowserService_OnHttpEquiv_Fn original_httpequiv, } } } - return original_httpequiv(browser, shell_view, done, in_arg, out_arg); } diff --git a/chrome_frame/bho.h b/chrome_frame/bho.h index c82f000..5992746 100644 --- a/chrome_frame/bho.h +++ b/chrome_frame/bho.h @@ -64,6 +64,10 @@ END_COM_MAP() BEGIN_SINK_MAP(Bho) SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2, BeforeNavigate2, &kBeforeNavigate2Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, + NavigateComplete2, &kNavigateComplete2Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR, + OnNavigateError, &kNavigateErrorInfo) END_SINK_MAP() // Lifetime management methods @@ -74,10 +78,17 @@ END_SINK_MAP() // IObjectWithSite STDMETHODIMP SetSite(IUnknown* site); + STDMETHOD(BeforeNavigate2)(IDispatch* dispatch, VARIANT* url, VARIANT* flags, VARIANT* target_frame_name, VARIANT* post_data, VARIANT* headers, VARIANT_BOOL* cancel); + STDMETHOD_(void, NavigateComplete2)(IDispatch* dispatch, VARIANT* url); + + STDMETHOD_(void, OnNavigateError)(IDispatch* dispatch, VARIANT* url, + VARIANT* frame_name, VARIANT* status_code, + VARIANT* cancel); + HRESULT NavigateToCurrentUrlInCF(IBrowserService* browser); // mshtml sends an IOleCommandTarget::Exec of OLECMDID_HTTPEQUIV @@ -113,6 +124,10 @@ END_SINK_MAP() static void ProcessOptInUrls(IWebBrowser2* browser, BSTR url); + int pending_navigation_count() const { + return pending_navigation_count_; + } + protected: bool PatchProtocolHandler(const CLSID& handler_clsid); @@ -122,6 +137,14 @@ END_SINK_MAP() static base::LazyInstance<base::ThreadLocalPointer<Bho> > bho_current_thread_instance_; static _ATL_FUNC_INFO kBeforeNavigate2Info; + static _ATL_FUNC_INFO kNavigateComplete2Info; + static _ATL_FUNC_INFO kNavigateErrorInfo; + + // This variable holds the pending navigation count seen by the BHO. It is + // incremented in BeforeNavigate2 and decremented in NavigateComplete2. + // Used to determine whether there are embedded frames loading for the + // current document. + int pending_navigation_count_; }; #endif // CHROME_FRAME_BHO_H_ diff --git a/chrome_frame/test/data/host_browser.html b/chrome_frame/test/data/host_browser.html new file mode 100644 index 0000000..cfd21f4 --- /dev/null +++ b/chrome_frame/test/data/host_browser.html @@ -0,0 +1,8 @@ +<html> + <head><title>Initial Page in host browser</title> + </head> + <body onLoad="test();"> + <h2>Initial page in host browser!</h2> + <p>This page should have loaded in the host browser.</p> + </body> +</html> diff --git a/chrome_frame/test/test_mock_with_web_server.cc b/chrome_frame/test/test_mock_with_web_server.cc index dd02150..83522aa 100644 --- a/chrome_frame/test/test_mock_with_web_server.cc +++ b/chrome_frame/test/test_mock_with_web_server.cc @@ -220,6 +220,19 @@ ACTION(DoCloseWindow) { ::PostMessage(arg0, WM_SYSCOMMAND, SC_CLOSE, 0); } +ACTION_P2(TypeUrlInAddressBar, loop, url) { + loop->PostDelayedTask(FROM_HERE, NewRunnableFunction( + simulate_input::SendCharA, 'd', simulate_input::ALT), + 1500); + + loop->PostDelayedTask(FROM_HERE, NewRunnableFunction( + simulate_input::SendStringW, url), 2000); + + loop->PostDelayedTask(FROM_HERE, NewRunnableFunction( + simulate_input::SendCharA, VK_RETURN, simulate_input::NONE), + 2000); +} + TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) { CloseIeAtEndOfScope last_resort_close_ie; chrome_frame_test::TimedMsgLoop loop; @@ -735,7 +748,7 @@ const wchar_t kBeforeUnloadMain[] = L"http://localhost:1337/files/fulltab_before_unload_event_main.html"; // http://code.google.com/p/chromium/issues/detail?id=37231 -TEST_F(ChromeFrameTestWithWebServer, DISABLED_FullTabModeIE_UnloadEventTest) { +TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_UnloadEventTest) { CloseIeAtEndOfScope last_resort_close_ie; chrome_frame_test::TimedMsgLoop loop; ComStackObjectWithUninitialize<MockWebBrowserEventSink> mock; @@ -1128,3 +1141,50 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_MenuSaveAs) { ASSERT_TRUE(DeleteFile(kSaveFileName)); } +const wchar_t kHostBrowserUrl[] = + L"http://localhost:1337/files/host_browser.html"; + +TEST_F(ChromeFrameTestWithWebServer, + FullTabMode_SwitchFromIEToChromeFrame) { + CloseIeAtEndOfScope last_resort_close_ie; + chrome_frame_test::TimedMsgLoop loop; + ComStackObjectWithUninitialize<MockWebBrowserEventSink> mock; + + EXPECT_CALL(mock, OnFileDownload(VARIANT_TRUE, _)) + .Times(testing::AnyNumber()); + + ::testing::InSequence sequence; // Everything in sequence + + // This test performs the following steps. + // 1. Launches IE and navigates to + // http://localhost:1337/files/back_to_ie.html, which should render in IE. + // 2. It then navigates to + // http://localhost:1337/files/sub_frame1.html which should render in + // ChromeFrame + EXPECT_CALL(mock, OnBeforeNavigate2(_, + testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kHostBrowserUrl)), _, _, _, _, _)); + + // When we receive a navigate complete notification for the initial URL + // initiate a navigation to a url which should be rendered in ChromeFrame. + EXPECT_CALL(mock, OnNavigateComplete2(_, + testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kHostBrowserUrl)))) + .Times(1) + .WillOnce(TypeUrlInAddressBar(&loop, kSubFrameUrl1)); + + mock.ExpectNavigationAndSwitch(kSubFrameUrl1); + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) + .WillOnce(CloseBrowserMock(&mock)); + + EXPECT_CALL(mock, OnQuit()).WillOnce(QUIT_LOOP(loop)); + + HRESULT hr = mock.LaunchIEAndNavigate(kHostBrowserUrl); + ASSERT_HRESULT_SUCCEEDED(hr); + if (hr == S_FALSE) + return; + + ASSERT_TRUE(mock.web_browser2() != NULL); + loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds * 2); +} + |