From 50b909a417cc85cc3f37c5b499d977d713a9d62d Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Tue, 4 Oct 2011 11:49:36 +0000 Subject: [PATCH] - Add a CefBrowser::ClearHistory() method for clearing back/forward browsing history (issue #352). - Move RegisterDevToolsSchemeHandler() call to CefContext::Initialize() to fix assertion when using multi-threaded message loop on Windows. - Add new NavigationTest.History test. - Remove unused RequestTest.HistoryNav test. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@301 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- cef.gyp | 1 + include/cef.h | 6 + include/cef_capi.h | 5 + libcef/browser_impl.cc | 23 +++ libcef/browser_impl.h | 1 + libcef/cef_context.cc | 5 + libcef/cef_process_ui_thread.cc | 5 - libcef_dll/cpptoc/browser_cpptoc.cc | 11 +- libcef_dll/ctocpp/browser_ctocpp.cc | 8 + libcef_dll/ctocpp/browser_ctocpp.h | 1 + tests/unittests/navigation_unittest.cc | 202 +++++++++++++++++++++++++ tests/unittests/request_unittest.cc | 139 +---------------- tests/unittests/test_handler.h | 3 + 13 files changed, 266 insertions(+), 144 deletions(-) create mode 100644 tests/unittests/navigation_unittest.cc diff --git a/cef.gyp b/cef.gyp index 66a4527a0..af3154920 100644 --- a/cef.gyp +++ b/cef.gyp @@ -232,6 +232,7 @@ 'tests/unittests/content_filter_unittest.cc', 'tests/unittests/cookie_unittest.cc', 'tests/unittests/dom_unittest.cc', + 'tests/unittests/navigation_unittest.cc', 'tests/unittests/request_unittest.cc', 'tests/unittests/run_all_unittests.cc', 'tests/unittests/scheme_handler_unittest.cc', diff --git a/include/cef.h b/include/cef.h index 426da5cb1..30d941288 100644 --- a/include/cef.h +++ b/include/cef.h @@ -704,6 +704,12 @@ public: /*--cef()--*/ virtual void SetZoomLevel(double zoomLevel) =0; + /// + // Clear the back/forward browsing history. + /// + /*--cef()--*/ + virtual void ClearHistory() =0; + /// // Open developer tools in its own window. /// diff --git a/include/cef_capi.h b/include/cef_capi.h index bc2e1e737..c4e5bcb71 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -534,6 +534,11 @@ typedef struct _cef_browser_t void (CEF_CALLBACK *set_zoom_level)(struct _cef_browser_t* self, double zoomLevel); + /// + // Clear the back/forward browsing history. + /// + void (CEF_CALLBACK *clear_history)(struct _cef_browser_t* self); + /// // Open developer tools in its own window. /// diff --git a/libcef/browser_impl.cc b/libcef/browser_impl.cc index 0c3d6ea58..f264c541b 100644 --- a/libcef/browser_impl.cc +++ b/libcef/browser_impl.cc @@ -307,6 +307,29 @@ void CefBrowserImpl::SetZoomLevel(double zoomLevel) &CefBrowserImpl::UIT_SetZoomLevel, zoomLevel)); } +void CefBrowserImpl::ClearHistory() +{ + if (CefThread::CurrentlyOn(CefThread::UI)) { + bool old_can_go_back = !nav_controller_->IsAtStart(); + bool old_can_go_forward = !nav_controller_->IsAtEnd(); + nav_controller_->Reset(); + + if (old_can_go_back || old_can_go_forward) { + set_nav_state(false, false); + if (client_.get()) { + CefRefPtr handler = client_->GetDisplayHandler(); + if (handler.get()) { + // Notify the handler of a navigation state change + handler->OnNavStateChange(this, false, false); + } + } + } + } else { + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::ClearHistory)); + } +} + void CefBrowserImpl::ShowDevTools() { CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, diff --git a/libcef/browser_impl.h b/libcef/browser_impl.h index 47b1d19a1..2292e7c8f 100644 --- a/libcef/browser_impl.h +++ b/libcef/browser_impl.h @@ -88,6 +88,7 @@ public: virtual void StopFinding(bool clearSelection) OVERRIDE; virtual double GetZoomLevel() OVERRIDE { return zoom_level(); } virtual void SetZoomLevel(double zoomLevel) OVERRIDE; + virtual void ClearHistory() OVERRIDE; virtual void ShowDevTools() OVERRIDE; virtual void CloseDevTools() OVERRIDE; virtual bool IsWindowRenderingDisabled() OVERRIDE; diff --git a/libcef/cef_context.cc b/libcef/cef_context.cc index eca8586d6..3a1ef1020 100644 --- a/libcef/cef_context.cc +++ b/libcef/cef_context.cc @@ -3,6 +3,7 @@ // be found in the LICENSE file. #include "cef_context.h" +#include "browser_devtools_scheme_handler.h" #include "browser_impl.h" #include "browser_webkit_glue.h" #include "cef_thread.h" @@ -505,6 +506,10 @@ bool CefContext::Initialize(const CefSettings& settings) initialized_ = true; + // Perform DevTools scheme registration when CEF initialization is complete. + CefThread::PostTask(CefThread::UI, FROM_HERE, + base::Bind(&RegisterDevToolsSchemeHandler)); + return true; } diff --git a/libcef/cef_process_ui_thread.cc b/libcef/cef_process_ui_thread.cc index d60e693d8..6928500be 100644 --- a/libcef/cef_process_ui_thread.cc +++ b/libcef/cef_process_ui_thread.cc @@ -14,7 +14,6 @@ #include "base/metrics/stats_table.h" #include "base/rand_util.h" #include "base/string_number_conversions.h" -#include "browser_devtools_scheme_handler.h" #include "build/build_config.h" #include "net/base/net_module.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebNetworkStateNotifier.h" @@ -156,10 +155,6 @@ void CefProcessUIThread::Init() { // Initialize WebKit with the current state. WebKit::WebNetworkStateNotifier::setOnLine( !net::NetworkChangeNotifier::IsOffline()); - - // Perform DevTools scheme registration when CEF initialization is complete. - CefThread::PostTask(CefThread::UI, FROM_HERE, - base::Bind(&RegisterDevToolsSchemeHandler)); } void CefProcessUIThread::CleanUp() { diff --git a/libcef_dll/cpptoc/browser_cpptoc.cc b/libcef_dll/cpptoc/browser_cpptoc.cc index ea8a4fdd1..ef19a3c77 100644 --- a/libcef_dll/cpptoc/browser_cpptoc.cc +++ b/libcef_dll/cpptoc/browser_cpptoc.cc @@ -307,12 +307,20 @@ void CEF_CALLBACK browser_set_zoom_level(struct _cef_browser_t* self, return CefBrowserCppToC::Get(self)->SetZoomLevel(zoomLevel); } -void CEF_CALLBACK browser_show_dev_tools(struct _cef_browser_t* self) +void CEF_CALLBACK browser_clear_history(struct _cef_browser_t* self) { DCHECK(self); if(!self) return; + CefBrowserCppToC::Get(self)->ClearHistory(); +} + +void CEF_CALLBACK browser_show_dev_tools(struct _cef_browser_t* self) +{ + DCHECK(self); + if(!self) + return; CefBrowserCppToC::Get(self)->ShowDevTools(); } @@ -491,6 +499,7 @@ CefBrowserCppToC::CefBrowserCppToC(CefBrowser* cls) struct_.struct_.stop_finding = browser_stop_finding; struct_.struct_.get_zoom_level = browser_get_zoom_level; struct_.struct_.set_zoom_level = browser_set_zoom_level; + struct_.struct_.clear_history = browser_clear_history; struct_.struct_.show_dev_tools = browser_show_dev_tools; struct_.struct_.close_dev_tools = browser_close_dev_tools; struct_.struct_.is_window_rendering_disabled = diff --git a/libcef_dll/ctocpp/browser_ctocpp.cc b/libcef_dll/ctocpp/browser_ctocpp.cc index 46b587d93..3b7d667c6 100644 --- a/libcef_dll/ctocpp/browser_ctocpp.cc +++ b/libcef_dll/ctocpp/browser_ctocpp.cc @@ -246,6 +246,14 @@ void CefBrowserCToCpp::SetZoomLevel(double zoomLevel) return struct_->set_zoom_level(struct_, zoomLevel); } +void CefBrowserCToCpp::ClearHistory() +{ + if (CEF_MEMBER_MISSING(struct_, clear_history)) + return; + + struct_->clear_history(struct_); +} + void CefBrowserCToCpp::ShowDevTools() { if (CEF_MEMBER_MISSING(struct_, show_dev_tools)) diff --git a/libcef_dll/ctocpp/browser_ctocpp.h b/libcef_dll/ctocpp/browser_ctocpp.h index fae861261..53700cb7c 100644 --- a/libcef_dll/ctocpp/browser_ctocpp.h +++ b/libcef_dll/ctocpp/browser_ctocpp.h @@ -55,6 +55,7 @@ public: virtual void StopFinding(bool clearSelection) OVERRIDE; virtual double GetZoomLevel() OVERRIDE; virtual void SetZoomLevel(double zoomLevel) OVERRIDE; + virtual void ClearHistory() OVERRIDE; virtual void ShowDevTools() OVERRIDE; virtual void CloseDevTools() OVERRIDE; virtual bool IsWindowRenderingDisabled() OVERRIDE; diff --git a/tests/unittests/navigation_unittest.cc b/tests/unittests/navigation_unittest.cc new file mode 100644 index 000000000..a9aef8fc6 --- /dev/null +++ b/tests/unittests/navigation_unittest.cc @@ -0,0 +1,202 @@ +// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "include/cef.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "test_handler.h" + +namespace { + +static const char* kNav1 = "http://tests/nav1.html"; +static const char* kNav2 = "http://tests/nav2.html"; +static const char* kNav3 = "http://tests/nav3.html"; + +enum NavAction { + NA_LOAD = 1, + NA_BACK, + NA_FORWARD, + NA_CLEAR +}; + +typedef struct { + NavAction action; // What to do + const char* target; // Where to be after navigation + bool can_go_back; // After navigation, can go back? + bool can_go_forward; // After navigation, can go forward? +} NavListItem; + +// Array of navigation actions: X = current page, . = history exists +static NavListItem kNavList[] = { + // kNav1 | kNav2 | kNav3 + {NA_LOAD, kNav1, false, false}, // X + {NA_LOAD, kNav2, true, false}, // . X + {NA_BACK, kNav1, false, true}, // X . + {NA_FORWARD, kNav2, true, false}, // . X + {NA_LOAD, kNav3, true, false}, // . . X + {NA_BACK, kNav2, true, true}, // . X . + {NA_CLEAR, kNav2, false, false}, // X +}; + +#define NAV_LIST_SIZE() (sizeof(kNavList) / sizeof(NavListItem)) + +class HistoryNavTestHandler : public TestHandler +{ +public: + HistoryNavTestHandler() : nav_(0) {} + + virtual void RunTest() OVERRIDE + { + // Add the resources that we will navigate to/from. + AddResource(kNav1, "Nav1", "text/html"); + AddResource(kNav2, "Nav2", "text/html"); + AddResource(kNav3, "Nav3", "text/html"); + + // Create the browser. + CreateBrowser(CefString()); + } + + void RunNav(CefRefPtr browser) + { + if (nav_ == NAV_LIST_SIZE()) { + // End of the nav list. + DestroyTest(); + return; + } + + const NavListItem& item = kNavList[nav_]; + + // Perform the action. + switch (item.action) { + case NA_LOAD: + browser->GetMainFrame()->LoadURL(item.target); + break; + case NA_BACK: + browser->GoBack(); + break; + case NA_FORWARD: + browser->GoForward(); + break; + case NA_CLEAR: + browser->ClearHistory(); + // Not really a navigation action so go to the next one. + nav_++; + RunNav(browser); + break; + default: + break; + } + } + + virtual void OnAfterCreated(CefRefPtr browser) OVERRIDE + { + TestHandler::OnAfterCreated(browser); + + RunNav(browser); + } + + virtual bool OnBeforeBrowse(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr request, + NavType navType, + bool isRedirect) OVERRIDE + { + const NavListItem& item = kNavList[nav_]; + + got_before_browse_[nav_].yes(); + + std::string url = request->GetURL(); + if (url == item.target) + got_correct_target_[nav_].yes(); + + if (((item.action == NA_BACK || item.action == NA_FORWARD) && + navType == NAVTYPE_BACKFORWARD) || + (item.action == NA_LOAD && navType == NAVTYPE_OTHER)) { + got_correct_nav_type_[nav_].yes(); + } + + return false; + } + + virtual void OnNavStateChange(CefRefPtr browser, + bool canGoBack, + bool canGoForward) OVERRIDE + { + const NavListItem& item = kNavList[nav_]; + + got_nav_state_change_[nav_].yes(); + + if (item.can_go_back == canGoBack) + got_correct_can_go_back_[nav_].yes(); + if (item.can_go_forward == canGoForward) + got_correct_can_go_forward_[nav_].yes(); + } + + virtual void OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) OVERRIDE + { + if(browser->IsPopup() || !frame->IsMain()) + return; + + const NavListItem& item = kNavList[nav_]; + + got_load_end_[nav_].yes(); + + if (item.can_go_back == browser->CanGoBack()) + got_correct_can_go_back2_[nav_].yes(); + if (item.can_go_forward == browser->CanGoForward()) + got_correct_can_go_forward2_[nav_].yes(); + + nav_++; + RunNav(browser); + } + + int nav_; + + TrackCallback got_before_browse_[NAV_LIST_SIZE()]; + TrackCallback got_correct_target_[NAV_LIST_SIZE()]; + TrackCallback got_correct_nav_type_[NAV_LIST_SIZE()]; + TrackCallback got_nav_state_change_[NAV_LIST_SIZE()]; + TrackCallback got_correct_can_go_back_[NAV_LIST_SIZE()]; + TrackCallback got_correct_can_go_forward_[NAV_LIST_SIZE()]; + TrackCallback got_load_end_[NAV_LIST_SIZE()]; + TrackCallback got_correct_can_go_back2_[NAV_LIST_SIZE()]; + TrackCallback got_correct_can_go_forward2_[NAV_LIST_SIZE()]; +}; + +} // namespace + +// Verify history navigation. +TEST(NavigationTest, History) +{ + CefRefPtr handler = + new HistoryNavTestHandler(); + handler->ExecuteTest(); + + for (int i = 0; i < NAV_LIST_SIZE(); ++i) { + if (kNavList[i].action != NA_CLEAR) { + ASSERT_TRUE(handler->got_before_browse_[i]) << "i = " << i; + ASSERT_TRUE(handler->got_correct_target_[i]) << "i = " << i; + ASSERT_TRUE(handler->got_correct_nav_type_[i]) << "i = " << i; + } + + if (i == 0 || kNavList[i].can_go_back != kNavList[i-1].can_go_back || + kNavList[i].can_go_forward != kNavList[i-1].can_go_forward) { + // Back/forward state has changed from one navigation to the next. + ASSERT_TRUE(handler->got_nav_state_change_[i]) << "i = " << i; + ASSERT_TRUE(handler->got_correct_can_go_back_[i]) << "i = " << i; + ASSERT_TRUE(handler->got_correct_can_go_forward_[i]) << "i = " << i; + } else { + ASSERT_FALSE(handler->got_nav_state_change_[i]) << "i = " << i; + ASSERT_FALSE(handler->got_correct_can_go_back_[i]) << "i = " << i; + ASSERT_FALSE(handler->got_correct_can_go_forward_[i]) << "i = " << i; + } + + if (kNavList[i].action != NA_CLEAR) { + ASSERT_TRUE(handler->got_load_end_[i]) << "i = " << i; + ASSERT_TRUE(handler->got_correct_can_go_back2_[i]) << "i = " << i; + ASSERT_TRUE(handler->got_correct_can_go_forward2_[i]) << "i = " << i; + } + } +} diff --git a/tests/unittests/request_unittest.cc b/tests/unittests/request_unittest.cc index 9a7862b19..2aa71f7cc 100644 --- a/tests/unittests/request_unittest.cc +++ b/tests/unittests/request_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. @@ -295,140 +295,3 @@ TEST(RequestTest, SendRecv) ASSERT_TRUE(g_RequestSendRecvTestHandlerHandleBeforeBrowseCalled); ASSERT_TRUE(g_RequestSendRecvTestHandlerHandleBeforeResourceLoadCalled); } - -// Enable this test if you have applied the patches for issue #42. -#if 0 - -bool g_RequestHistoryNavTestDidLoadRequest; -bool g_RequestHistoryNavTestDidReloadRequest; - -class RequestHistoryNavTestHandler : public TestHandler -{ -public: - RequestHistoryNavTestHandler() : navigated_(false) {} - - virtual void RunTest() - { - // Create the test request - CreateRequest(request_); - - // Add the resource that we will navigate to/from - AddResource("http://tests/goto.html", "To", "text/html"); - - // Create the browser - CreateBrowser(CefString()); - } - - virtual RetVal HandleAfterCreated(CefRefPtr browser) - { - TestHandler::HandleAfterCreated(browser); - - // Load the test request - browser->GetMainFrame()->LoadRequest(request_); - return RV_CONTINUE; - } - - virtual RetVal HandleBeforeBrowse(CefRefPtr browser, - CefRefPtr frame, - CefRefPtr request, - NavType navType, bool isRedirect) - { - CefString url = request->GetURL(); - if(url == "http://tests/run.html") - { - // Verify that the request is the same - VerifyRequestEqual(request_, request, true); - } - - return RV_CONTINUE; - } - - virtual RetVal HandleBeforeResourceLoad(CefRefPtr browser, - CefRefPtr request, - CefString& redirectUrl, - CefRefPtr& resourceStream, - CefString& mimeType, - int loadFlags) - { - CefString url = request->GetURL(); - if(url == "http://tests/run.html") - { - // Verify that the request is the same - VerifyRequestEqual(request_, request, true); - - if(!navigated_) - { - // Loading the request for the 1st time - g_RequestHistoryNavTestDidLoadRequest = true; - } - else - { - // Re-loading the request - g_RequestHistoryNavTestDidReloadRequest = true; - } - - // Return dummy results - std::string output = "Request"; - resourceStream = CefStreamReader::CreateForData((void*)output.c_str(), - output.length()); - mimeType = "text/html"; - return RV_CONTINUE; - } - else - { - // Pass to the default handler to return the to/from page - return TestHandler::HandleBeforeResourceLoad(browser, request, - redirectUrl, resourceStream, mimeType, loadFlags); - } - } - - virtual RetVal HandleLoadEnd(CefRefPtr browser, - CefRefPtr frame, - int httpStatusCode) - { - if(!browser->IsPopup() && frame->IsMain()) - { - CefString url = browser->GetMainFrame()->GetURL(); - if(url == "http://tests/run.html") - { - if(!navigated_) - { - // First resource load, go to the next page - navigated_ = true; - browser->GetMainFrame()->LoadURL("http://tests/goto.html"); - } - else - { - // Resource re-load, end the test - DestroyTest(); - } - } - else - { - // To/from page load, go back the the request page - browser->GoBack(); - } - } - return RV_CONTINUE; - } - - CefRefPtr request_; - bool navigated_; -}; - -// Verify history navigation -// This test will only pass if the patches for issue #42 are applied. -TEST(RequestTest, HistoryNav) -{ - g_RequestHistoryNavTestDidLoadRequest = false; - g_RequestHistoryNavTestDidReloadRequest = false; - - CefRefPtr handler = - new RequestHistoryNavTestHandler(); - handler->ExecuteTest(); - - ASSERT_TRUE(g_RequestHistoryNavTestDidLoadRequest); - ASSERT_TRUE(g_RequestHistoryNavTestDidReloadRequest); -} - -#endif // 0 diff --git a/tests/unittests/test_handler.h b/tests/unittests/test_handler.h index a4ba7c111..a0e29cf3c 100644 --- a/tests/unittests/test_handler.h +++ b/tests/unittests/test_handler.h @@ -24,6 +24,7 @@ protected: // Base implementation of CefClient for unit tests. Add new interfaces as needed // by test cases. class TestHandler : public CefClient, + public CefDisplayHandler, public CefLifeSpanHandler, public CefLoadHandler, public CefRequestHandler, @@ -42,6 +43,8 @@ public: virtual void RunTest() =0; // CefClient methods. Add new methods as needed by test cases. + virtual CefRefPtr GetDisplayHandler() OVERRIDE + { return this; } virtual CefRefPtr GetLifeSpanHandler() OVERRIDE { return this; } virtual CefRefPtr GetLoadHandler() OVERRIDE