summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome_frame/bho.cc40
-rw-r--r--chrome_frame/test/data/host_browser.html7
-rw-r--r--chrome_frame/test/test_mock_with_web_server.cc92
3 files changed, 128 insertions, 11 deletions
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc
index c5c8aa0..aa333b7 100644
--- a/chrome_frame/bho.cc
+++ b/chrome_frame/bho.cc
@@ -165,8 +165,44 @@ bool DocumentHasEmbeddedItems(IUnknown* browser) {
if (enumerator) {
ScopedComPtr<IUnknown> unk;
DWORD fetched = 0;
- enumerator->Next(1, unk.Receive(), &fetched);
- has_embedded_items = (fetched != 0);
+ while (!has_embedded_items &&
+ SUCCEEDED(enumerator->Next(1, unk.Receive(), &fetched))
+ && fetched) {
+ // If a top level document has embedded iframes then the theory is
+ // that first the top level document finishes loading and then the
+ // iframes load. We should only treat an embedded element as an
+ // iframe if it supports the IWebBrowser interface.
+ ScopedComPtr<IWebBrowser2> embedded_web_browser2;
+ if (SUCCEEDED(embedded_web_browser2.QueryFrom(unk))) {
+ // If we initiate a top level navigation then at times MSHTML
+ // creates a temporary IWebBrowser2 interface which basically shows
+ // up as a temporary iframe in the parent document. It is not clear
+ // as to how we can detect this. I tried the usual stuff like
+ // getting to the parent IHTMLWindow2 interface. They all end up
+ // pointing to dummy tear off interfaces owned by MSHTML.
+ // As a temporary workaround, we found that the location url in
+ // this case is about:blank. We now check for the same and don't
+ // treat it as an iframe. This should be fine in most cases as we
+ // hit this code only when the actual page has a meta tag. However
+ // this would break for cases like the initial src url for an
+ // iframe pointing to about:blank and the page then writing to it
+ // via document.write.
+ // TODO(ananta)
+ // Revisit this and come up with a better approach.
+ ScopedBstr location_url;
+ embedded_web_browser2->get_LocationURL(location_url.Receive());
+
+ std::wstring location_url_string;
+ location_url_string.assign(location_url, location_url.Length());
+
+ if (!LowerCaseEqualsASCII(location_url_string, "about:blank")) {
+ has_embedded_items = true;
+ }
+ }
+
+ fetched = 0;
+ unk.Release();
+ }
}
}
}
diff --git a/chrome_frame/test/data/host_browser.html b/chrome_frame/test/data/host_browser.html
new file mode 100644
index 0000000..b6471f6
--- /dev/null
+++ b/chrome_frame/test/data/host_browser.html
@@ -0,0 +1,7 @@
+<html>
+ <head><title>Initial Page in host browser</title>
+ <body>
+ <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..4a8f76b 100644
--- a/chrome_frame/test/test_mock_with_web_server.cc
+++ b/chrome_frame/test/test_mock_with_web_server.cc
@@ -220,6 +220,31 @@ ACTION(DoCloseWindow) {
::PostMessage(arg0, WM_SYSCOMMAND, SC_CLOSE, 0);
}
+// This function selects the address bar via the Alt+d shortcut. This is done
+// via a delayed task which executes after the delay which is passed in.
+// The subsequent operations like typing in the actual url and then hitting
+// enter to force the browser to navigate to it each execute as delayed tasks
+// timed at the delay passed in. The recommended value for delay is 2000 ms
+// to account for the time taken for the accelerator keys to be reflected back
+// from Chrome.
+ACTION_P3(TypeUrlInAddressBar, loop, url, delay) {
+ loop->PostDelayedTask(FROM_HERE, NewRunnableFunction(
+ simulate_input::SendCharA, 'd', simulate_input::ALT),
+ delay);
+
+ const unsigned long kInterval = 25;
+ int next_delay = delay + kInterval;
+
+ loop->PostDelayedTask(FROM_HERE, NewRunnableFunction(
+ simulate_input::SendStringW, url), next_delay);
+
+ next_delay = next_delay + kInterval;
+
+ loop->PostDelayedTask(FROM_HERE, NewRunnableFunction(
+ simulate_input::SendCharA, VK_RETURN, simulate_input::NONE),
+ next_delay);
+}
+
TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) {
CloseIeAtEndOfScope last_resort_close_ie;
chrome_frame_test::TimedMsgLoop loop;
@@ -452,9 +477,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_AltD) {
EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1)))
.WillOnce(testing::DoAll(
SetFocusToChrome(&mock),
- DelaySendChar(&loop, 1500, 'd', simulate_input::ALT),
- DelaySendString(&loop, 2000, kSubFrameUrl2),
- DelaySendChar(&loop, 2200, VK_RETURN, simulate_input::NONE)));
+ TypeUrlInAddressBar(&loop, kSubFrameUrl2, 1500)));
mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl2);
EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2)))
@@ -551,7 +574,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) {
// We have reached url 2 and have 1 back & 1 forward entries for url 1 & 3
// Go back to url 1 now
- mock.ExpectNavigation(kSubFrameUrl2);
+ mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl2);
EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2)))
.WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(
CreateFunctor(ReceivePointer(mock.web_browser2_),
@@ -559,7 +582,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) {
// We have reached url 1 and have 0 back & 2 forward entries for url 2 & 3
// Go back to url 1 now
- mock.ExpectNavigation(kSubFrameUrl1);
+ mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl1);
EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1)))
.WillOnce(CloseBrowserMock(&mock));
EXPECT_CALL(mock, OnQuit()).WillOnce(QUIT_LOOP(loop));
@@ -826,14 +849,14 @@ TEST_F(ChromeFrameTestWithWebServer,
.WillOnce(testing::DoAll(
DelaySendMouseClick(&mock, &loop, 0, 10, 10, simulate_input::RIGHT),
SendExtendedKeysEnter(&loop, 500, VK_DOWN, 1, simulate_input::NONE)));
- mock.ExpectNavigation(kSubFrameUrl1);
+ mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl1);
// Go forward using Rt-Click + DOWN + DOWN + ENTER
EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1)))
.WillOnce(testing::DoAll(
DelaySendMouseClick(&mock, &loop, 0, 10, 10, simulate_input::RIGHT),
SendExtendedKeysEnter(&loop, 500, VK_DOWN, 2, simulate_input::NONE)));
- mock.ExpectNavigation(kSubFrameUrl2);
+ mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl2);
EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2)))
.WillOnce(CloseBrowserMock(&mock));
@@ -1064,15 +1087,16 @@ TEST_F(ChromeFrameTestWithWebServer,
SetFocusToChrome(&mock),
DelaySendScanCode(&loop, 500, bkspace, simulate_input::NONE)));
- mock.ExpectNavigation(kSubFrameUrl1);
+ mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl1);
EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1)))
.WillOnce(testing::DoAll(
SetFocusToChrome(&mock),
DelaySendScanCode(&loop, 1500, bkspace, simulate_input::SHIFT)));
- mock.ExpectNavigation(kSubFrameUrl2);
+ mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl2);
EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2)))
.WillOnce(CloseBrowserMock(&mock));
+
EXPECT_CALL(mock, OnQuit()).WillOnce(QUIT_LOOP(loop));
HRESULT hr = mock.LaunchIEAndNavigate(kSubFrameUrl1);
@@ -1128,3 +1152,53 @@ 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,
+ FLAKY_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, 1500));
+
+ EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kHostBrowserUrl)))
+ .Times(0);
+
+ 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);
+}
+