diff options
author | finnur@google.com <finnur@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-24 00:10:29 +0000 |
---|---|---|
committer | finnur@google.com <finnur@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-24 00:10:29 +0000 |
commit | 4f3dc3751d69f9db1f8ef533a3335201b3bc78bc (patch) | |
tree | e37efecf992ddd4e901c894273cbb1e5bf4260cc | |
parent | 5e7f161f73f1817b8a0c422c0e4b5eceae6954e7 (diff) | |
download | chromium_src-4f3dc3751d69f9db1f8ef533a3335201b3bc78bc.zip chromium_src-4f3dc3751d69f9db1f8ef533a3335201b3bc78bc.tar.gz chromium_src-4f3dc3751d69f9db1f8ef533a3335201b3bc78bc.tar.bz2 |
The find bar should be owned and managed from the BrowserView, not the WebContentsView, since it's part of the "chrome".
Design Doc: http://dev.chromium.org/developers/design-documents/find-bar
Things done:
- Pulled all of the find bar stuff out of WebContentsView* since it's no longer needed.
- Moved OnFindReply delegate method from RenderViewHostDelegate::View to RenderViewHostDelegate, since it's no longer implemented on the view.
- Moved find control methods to WebContents.
- Added recent find result state to WebContents.
- Updated the UI tests to accommodate the changes in the state that is broadcast when results are discovered.
- Updated the find bar layout to obtain its bounding box from the BrowserView, which knows about toolbars, bookmark bars etc.
- Updated the find bar itself to handle the fact that it can be displayed for multiple different tabs.
- Moved the find bar manipulation methods for testing from TabProxy to BrowserProxy, since the find bar is now a feature of the window, not the tab.
- view.h: Don't lay out child views again if they have a layout manager, it already updated them.
TEST=Find box should work as before.
BUG=3245
Review URL: http://codereview.chromium.org/27025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10231 0039d316-1c4b-4281-b951-d872f2087c98
35 files changed, 747 insertions, 836 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 013325c..926e507 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -7,7 +7,7 @@ #include "base/message_loop.h" #include "base/path_service.h" #include "base/thread.h" -#include "chrome/app/chrome_dll_resource.h" +#include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/app_modal_dialog_queue.h" #include "chrome/browser/automation/automation_provider_list.h" #include "chrome/browser/automation/ui_controls.h" @@ -268,8 +268,8 @@ class NavigationNotificationObserver : public NotificationObserver { // afer the load has started (but not after the entry was committed, as // WaitForNavigation compares times of the last navigation). // - when this is used with a page requiring authentication, we will not get - // a NotificationType::NAV_ENTRY_COMMITTED until after we authenticate, so we need the - // NotificationType::LOAD_START. + // a NotificationType::NAV_ENTRY_COMMITTED until after we authenticate, so + // we need the NotificationType::LOAD_START. if (type == NotificationType::NAV_ENTRY_COMMITTED || type == NotificationType::LOAD_START) { navigation_started_ = true; @@ -360,7 +360,7 @@ class TabStripNotificationObserver : public NotificationObserver { class TabAppendedNotificationObserver : public TabStripNotificationObserver { public: TabAppendedNotificationObserver(Browser* parent, - AutomationProvider* automation, int32 routing_id, + AutomationProvider* automation, int32 routing_id, IPC::Message* reply_message) : TabStripNotificationObserver(parent, NotificationType::TAB_PARENTED, automation, routing_id), @@ -657,7 +657,7 @@ class AutomationInterstitialPage : public InterstitialPage { private: std::string contents_; - + DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage); }; @@ -1604,7 +1604,7 @@ void AutomationProvider::OnRedirectQueryComplete( reply_message_->WriteInt(-1); // Negative count indicates failure. } - IPC::ParamTraits<std::vector<GURL>>::Write(reply_message_, redirects_gurl); + IPC::ParamTraits<std::vector<GURL> >::Write(reply_message_, redirects_gurl); Send(reply_message_); redirect_query_ = NULL; @@ -1806,14 +1806,10 @@ void AutomationProvider::HandleFindRequest(int handle, reply_message->routing_id(), reply_message)); - // The find in page dialog must be up for us to get the notification that the - // find was complete. WebContents* web_contents = tab_contents->AsWebContents(); if (web_contents) { - NavigationController* tab = tab_tracker_->GetResource(handle); - Browser* browser = Browser::GetBrowserForController(tab, NULL); - web_contents->view()->FindInPage(*browser, true, request.forward); - + web_contents->set_current_find_request_id( + FindInPageNotificationObserver::kFindInPageRequestId); web_contents->render_view_host()->StartFinding( FindInPageNotificationObserver::kFindInPageRequestId, request.search_string, request.forward, request.match_case, @@ -1823,29 +1819,33 @@ void AutomationProvider::HandleFindRequest(int handle, void AutomationProvider::HandleOpenFindInPageRequest( const IPC::Message& message, int handle) { - NavigationController* tab = NULL; - WebContents* web_contents = GetWebContentsForHandle(handle, &tab); - if (web_contents) { - Browser* browser = Browser::GetBrowserForController(tab, NULL); - web_contents->view()->FindInPage(*browser, false, false); + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + browser->FindInPage(false, false); } } void AutomationProvider::GetFindWindowVisibility(int handle, bool* visible) { gfx::Point position; *visible = false; - WebContents* web_contents = GetWebContentsForHandle(handle, NULL); - if (web_contents) - web_contents->view()->GetFindBarWindowInfo(&position, visible); + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + BrowserWindowTesting* testing = + browser->window()->GetBrowserWindowTesting(); + testing->GetFindBarWindowInfo(&position, visible); + } } void AutomationProvider::HandleFindWindowLocationRequest(int handle, int* x, int* y) { gfx::Point position(0, 0); bool visible = false; - WebContents* web_contents = GetWebContentsForHandle(handle, NULL); - if (web_contents) - web_contents->view()->GetFindBarWindowInfo(&position, &visible); + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + BrowserWindowTesting* testing = + browser->window()->GetBrowserWindowTesting(); + testing->GetFindBarWindowInfo(&position, &visible); + } *x = position.x(); *y = position.y(); @@ -1926,8 +1926,8 @@ void AutomationProvider::SetFilteredInet(const IPC::Message& message, new SetFilteredInetTask(enabled)); } -void AutomationProvider::GetDownloadDirectory(int handle, - std::wstring* download_directory) { +void AutomationProvider::GetDownloadDirectory( + int handle, std::wstring* download_directory) { DLOG(INFO) << "Handling download directory request"; if (tab_tracker_->ContainsHandle(handle)) { NavigationController* tab = tab_tracker_->GetResource(handle); @@ -2427,7 +2427,8 @@ void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) { // want the automation provider (and hence the process) to go away when the // last browser goes away. if (BrowserList::size() == 1) { - // If you change this, update Observer for NotificationType::SESSION_END below. + // If you change this, update Observer for NotificationType::SESSION_END + // below. MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider)); } @@ -2478,7 +2479,7 @@ void AutomationProvider::ClickSSLInfoBarLink(int handle, success = true; } } - } + } if (!wait_for_navigation || !success) AutomationMsg_ClickSSLInfoBarLink::WriteReplyParams(reply_message, success); @@ -2501,7 +2502,7 @@ void AutomationProvider::WaitForNavigation(int handle, if (time.ToInternalValue() > last_navigation_time || !controller) { AutomationMsg_WaitForNavigation::WriteReplyParams(reply_message, controller != NULL); - return; + return; } AddNavigationStatusListener<bool>(controller, reply_message, true, true, diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index d91c114..9c479a6 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -845,18 +845,17 @@ void Browser::Paste() { void Browser::Find() { UserMetrics::RecordAction(L"Find", profile_); - GetSelectedTabContents()->AsWebContents()->view()->FindInPage(*this, false, - false); + FindInPage(false, false); } void Browser::FindNext() { UserMetrics::RecordAction(L"FindNext", profile_); - AdvanceFindSelection(true); + FindInPage(true, true); } void Browser::FindPrevious() { UserMetrics::RecordAction(L"FindPrevious", profile_); - AdvanceFindSelection(false); + FindInPage(true, false); } void Browser::ZoomIn() { @@ -1238,20 +1237,6 @@ void Browser::CreateNewStripWithContents(TabContents* detached_contents, // won't start if the page is loading. browser->LoadingStateChanged(detached_contents); browser->window()->Show(); - -#if defined(OS_WIN) - // When we detach a tab we need to make sure any associated Find window moves - // along with it to its new home (basically we just make new_window the - // parent of the Find window). - // TODO(brettw) this could probably be improved, see - // WebContentsView::ReparentFindWindow for more. - WebContents* web_contents = detached_contents->AsWebContents(); - if (web_contents) - web_contents->view()->ReparentFindWindow(browser); -#else - // TODO(port): remove the view dependency from this. - NOTIMPLEMENTED() << "need to reparent find window"; -#endif } int Browser::GetDragActions() const { @@ -1398,18 +1383,6 @@ void Browser::TabInsertedAt(TabContents* contents, SyncHistoryWithTabs(tabstrip_model_.GetIndexOfTabContents(contents)); -#if defined(OS_WIN) - // When a tab is dropped into a tab strip we need to make sure that the - // associated Find window is moved along with it. We therefore change the - // parent of the Find window (if the parent is already correctly set this - // does nothing). - // TODO(brettw) this could probably be improved, see - // WebContentsView::ReparentFindWindow for more. - WebContents* web_contents = contents->AsWebContents(); - if (web_contents) - web_contents->view()->ReparentFindWindow(this); -#endif - // Make sure the loading state is updated correctly, otherwise the throbber // won't start if the page is loading. LoadingStateChanged(contents); @@ -2407,11 +2380,14 @@ GURL Browser::GetHomePage() { } #if defined(OS_WIN) -void Browser::AdvanceFindSelection(bool forward_direction) { - GetSelectedTabContents()->AsWebContents()->view()->FindInPage( - *this, true, forward_direction); +void Browser::FindInPage(bool find_next, bool forward_direction) { + window_->ShowFindBar(); + if (find_next) { + GetSelectedTabContents()->AsWebContents()->StartFinding( + std::wstring(), + forward_direction); + } } - #endif // OS_WIN void Browser::CloseFrame() { diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index cce7bfc..828e9c6 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -508,9 +508,10 @@ class Browser : public TabStripModelDelegate, GURL GetHomePage(); #if defined(OS_WIN) - // Advance the find selection by one. Direction is either forward or - // backwards depending on parameter passed in. - void AdvanceFindSelection(bool forward_direction); + // Shows the Find Bar, optionally selecting the next entry that matches the + // existing search string for that Tab. |forward_direction| controls the + // search direction. + void FindInPage(bool find_next, bool forward_direction); #endif // Closes the frame. @@ -571,7 +572,7 @@ class Browser : public TabStripModelDelegate, private: Browser* browser_; - DISALLOW_EVIL_CONSTRUCTORS(BrowserToolbarModel); + DISALLOW_COPY_AND_ASSIGN(BrowserToolbarModel); }; // The model for the toolbar view. diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index be21a1a..8a5ff21 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -16,6 +16,7 @@ class StatusBubble; class TabContents; namespace gfx { +class Point; class Rect; } @@ -123,6 +124,9 @@ class BrowserWindow { // Shows or hides the bookmark bar depending on its current visibility. virtual void ToggleBookmarkBar() = 0; + // Shows the Find Bar. + virtual void ShowFindBar() = 0; + // Shows the About Chrome dialog box. virtual void ShowAboutChromeDialog() = 0; @@ -182,7 +186,16 @@ class BrowserWindowTesting { // Returns the LocationBarView. virtual LocationBarView* GetLocationBarView() const = 0; + + // Computes the location of the find bar and whether it is fully visible in + // its parent window. The return value indicates if the window is visible at + // all. Both out arguments are required. + // + // This is used for UI tests of the find bar. If the find bar is not currently + // shown (return value of false), the out params will be {(0, 0), false}. + virtual bool GetFindBarWindowInfo(gfx::Point* position, + bool* fully_visible) const = 0; #endif }; -#endif // CHROME_BROWSER_BROWSER_WINDOW_H__ +#endif // CHROME_BROWSER_BROWSER_WINDOW_H_ diff --git a/chrome/browser/cocoa/browser_window_cocoa.h b/chrome/browser/cocoa/browser_window_cocoa.h index 1f7f59b..d4b3ffb 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.h +++ b/chrome/browser/cocoa/browser_window_cocoa.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_WINDOW_COCOA_H_ -#define CHROME_BROWSER_WINDOW_COCOA_H_ +#ifndef CHROME_BROWSER_COCOA_BROWSER_WINDOW_COCOA_H_ +#define CHROME_BROWSER_COCOA_BROWSER_WINDOW_COCOA_H_ #include "chrome/browser/browser_window.h" @@ -18,7 +18,7 @@ class BrowserWindowCocoa : public BrowserWindow { public: BrowserWindowCocoa(BrowserWindowController* controller, NSWindow* window); virtual ~BrowserWindowCocoa(); - + // Overridden from BrowserWindow virtual void Init(); virtual void Show(); @@ -46,6 +46,7 @@ class BrowserWindowCocoa : public BrowserWindow { virtual bool IsBookmarkBarVisible() const; virtual gfx::Rect GetRootWindowResizerRect() const; virtual void ToggleBookmarkBar(); + virtual void ShowFindBar(); virtual void ShowAboutChromeDialog(); virtual void ShowBookmarkManager(); virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked); @@ -58,13 +59,12 @@ class BrowserWindowCocoa : public BrowserWindow { virtual void ShowNewProfileDialog(); virtual void ShowHTMLDialog(HtmlDialogContentsDelegate* delegate, void* parent_window); - protected: virtual void DestroyBrowser(); - + private: BrowserWindowController* controller_; // weak, owns us NSWindow* window_; // weak, owned by |controller_| }; -#endif // CHROME_BROWSER_WINDOW_COCOA_H_ +#endif // CHROME_BROWSER_COCOA_BROWSER_WINDOW_COCOA_H_ diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm index d54d0c7..6af331b 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/cocoa/browser_window_cocoa.mm @@ -135,6 +135,10 @@ void BrowserWindowCocoa::ToggleBookmarkBar() { NOTIMPLEMENTED(); } +void BrowserWindowCocoa::ShowFindBar() { + NOTIMPLEMENTED(); +} + void BrowserWindowCocoa::ShowAboutChromeDialog() { NOTIMPLEMENTED(); } diff --git a/chrome/browser/find_notification_details.h b/chrome/browser/find_notification_details.h index 23033ae..45dd331 100644 --- a/chrome/browser/find_notification_details.h +++ b/chrome/browser/find_notification_details.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H__ -#define CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H__ +#ifndef CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H_ +#define CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H_ #include "base/basictypes.h" #include "base/gfx/rect.h" @@ -21,6 +21,12 @@ class FindNotificationDetails { active_match_ordinal_(active_match_ordinal), final_update_(final_update) {} + FindNotificationDetails() + : request_id_(0), + number_of_matches_(-1), + active_match_ordinal_(-1), + final_update_(false) {} + ~FindNotificationDetails() {} int request_id() const { return request_id_; } @@ -39,11 +45,6 @@ class FindNotificationDetails { gfx::Rect selection_rect_; // Where selection occurred (screen coordinate). int active_match_ordinal_; // The ordinal of the currently selected match. bool final_update_; // Whether this is the last Find Result update. - - FindNotificationDetails() {} - - DISALLOW_EVIL_CONSTRUCTORS(FindNotificationDetails); }; -#endif // CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H__ - +#endif // CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H_ diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index 06ad7af..6535539 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -290,6 +290,10 @@ void BrowserWindowGtk::ToggleBookmarkBar() { NOTIMPLEMENTED(); } +void BrowserWindowGtk::ShowFindBar() { + NOTIMPLEMENTED(); +} + void BrowserWindowGtk::ShowAboutChromeDialog() { NOTIMPLEMENTED(); } diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h index 70ed990..adc1e91 100644 --- a/chrome/browser/gtk/browser_window_gtk.h +++ b/chrome/browser/gtk/browser_window_gtk.h @@ -54,6 +54,7 @@ class BrowserWindowGtk : public BrowserWindow, virtual bool IsBookmarkBarVisible() const; virtual gfx::Rect GetRootWindowResizerRect() const; virtual void ToggleBookmarkBar(); + virtual void ShowFindBar(); virtual void ShowAboutChromeDialog(); virtual void ShowBookmarkManager(); virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked); diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index ae84b8f..723e91e9 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -966,11 +966,8 @@ void RenderViewHost::OnMsgFindReply(int request_id, const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update) { - RenderViewHostDelegate::View* view = delegate_->GetViewDelegate(); - if (!view) - return; - view->OnFindReply(request_id, number_of_matches, selection_rect, - active_match_ordinal, final_update); + delegate_->OnFindReply(request_id, number_of_matches, selection_rect, + active_match_ordinal, final_update); // Send a notification to the renderer that we are ready to receive more // results from the scoping effort of the Find operation. The FindInPage diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h index 7cfe6f9..67ac07e 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.h +++ b/chrome/browser/renderer_host/render_view_host_delegate.h @@ -112,13 +112,6 @@ class RenderViewHostDelegate { // specified events. This gives an opportunity to the browser to process the // event (used for keyboard shortcuts). virtual void HandleKeyboardEvent(const WebKeyboardEvent& event) = 0; - - // A find operation in the current page completed. - virtual void OnFindReply(int request_id, - int number_of_matches, - const gfx::Rect& selection_rect, - int active_match_ordinal, - bool final_update) = 0; }; // Interface for saving web pages. @@ -401,7 +394,13 @@ class RenderViewHostDelegate { // If this view can be terminated without any side effects virtual bool CanTerminate() const { return true; } + + // A find operation in the current page completed. + virtual void OnFindReply(int request_id, + int number_of_matches, + const gfx::Rect& selection_rect, + int active_match_ordinal, + bool final_update) { } }; #endif // CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_DELEGATE_H_ - diff --git a/chrome/browser/tab_contents/web_contents.cc b/chrome/browser/tab_contents/web_contents.cc index 54b8d6e..ecf33c9 100644 --- a/chrome/browser/tab_contents/web_contents.cc +++ b/chrome/browser/tab_contents/web_contents.cc @@ -182,6 +182,9 @@ class WebContents::GearsCreateShortcutCallbackFunctor { WebContents* contents_; }; +// static +int WebContents::find_request_id_counter_ = -1; + WebContents::WebContents(Profile* profile, SiteInstance* site_instance, RenderViewHostFactory* render_view_factory, @@ -201,8 +204,10 @@ WebContents::WebContents(Profile* profile, #endif ALLOW_THIS_IN_INITIALIZER_LIST(fav_icon_helper_(this)), suppress_javascript_messages_(false), - load_state_(net::LOAD_STATE_IDLE) { - + load_state_(net::LOAD_STATE_IDLE), + find_ui_active_(false), + find_op_aborted_(false), + current_find_request_id_(find_request_id_counter_++) { pending_install_.page_id = 0; pending_install_.callback_functor = NULL; @@ -532,6 +537,43 @@ void WebContents::CreateShortcut() { render_view_host()->GetApplicationInfo(pending_install_.page_id); } +void WebContents::StartFinding(const std::wstring& find_text, + bool forward_direction) { + // If find_text is empty, it means FindNext was pressed with a keyboard + // shortcut so unless we have something to search for we return early. + if (find_text.empty() && find_text_.empty()) + return; + + // This is a FindNext operation if we are searching for the same text again, + // or if the passed in search text is empty (FindNext keyboard shortcut). The + // exception to this is if the Find was aborted (then we don't want FindNext + // because the highlighting has been cleared and we need it to reappear). We + // therefore treat FindNext after an aborted Find operation as a full fledged + // Find. + bool find_next = (find_text_ == find_text || find_text.empty()) && + !find_op_aborted_; + if (!find_next) + current_find_request_id_ = find_request_id_counter_++; + + if (!find_text.empty()) + find_text_ = find_text; + + find_op_aborted_ = false; + + render_view_host()->StartFinding(current_find_request_id_, + find_text_, + forward_direction, + false, // case sensitive + find_next); +} + +void WebContents::StopFinding(bool clear_selection) { + find_ui_active_ = false; + find_op_aborted_ = true; + find_result_ = FindNotificationDetails(); + render_view_host()->StopFinding(clear_selection); +} + void WebContents::OnJavaScriptMessageBoxClosed(IPC::Message* reply_msg, bool success, const std::wstring& prompt) { @@ -591,9 +633,6 @@ bool WebContents::PrintNow() { if (showing_interstitial_page()) return false; - // If we have a find bar it needs to hide as well. - view_->HideFindBar(false); - return render_view_host()->PrintPages(); } @@ -1356,6 +1395,33 @@ void WebContents::OnEnterOrSpace() { #endif } +void WebContents::OnFindReply(int request_id, + int number_of_matches, + const gfx::Rect& selection_rect, + int active_match_ordinal, + bool final_update) { + // Ignore responses for requests other than the one we have most recently + // issued. That way we won't act on stale results when the user has + // already typed in another query. + if (request_id != current_find_request_id_) + return; + + if (number_of_matches == -1) + number_of_matches = find_result_.number_of_matches(); + if (active_match_ordinal == -1) + active_match_ordinal = find_result_.active_match_ordinal(); + + // Notify the UI, automation and any other observers that a find result was + // found. + find_result_ = FindNotificationDetails(request_id, number_of_matches, + selection_rect, active_match_ordinal, + final_update); + NotificationService::current()->Notify( + NotificationType::FIND_RESULT_AVAILABLE, + Source<TabContents>(this), + Details<FindNotificationDetails>(&find_result_)); +} + bool WebContents::CanTerminate() const { if (!delegate()) return true; @@ -1498,12 +1564,6 @@ void WebContents::DidNavigateMainFramePostCommit( // Close constrained popups if necessary. MaybeCloseChildWindows(details.previous_url, details.entry->url()); - // We hide the FindInPage window when the user navigates away, except on - // reload. - if (PageTransition::StripQualifier(params.transition) != - PageTransition::RELOAD) - view_->HideFindBar(true); - // Update the starred state. UpdateStarredStateForCurrentURL(); } diff --git a/chrome/browser/tab_contents/web_contents.h b/chrome/browser/tab_contents/web_contents.h index 52b48fe..08ac907 100644 --- a/chrome/browser/tab_contents/web_contents.h +++ b/chrome/browser/tab_contents/web_contents.h @@ -14,6 +14,7 @@ #include "chrome/browser/cancelable_request.h" #include "chrome/browser/download/save_package.h" #include "chrome/browser/fav_icon_helper.h" +#include "chrome/browser/find_notification_details.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/render_view_host_manager.h" @@ -171,6 +172,40 @@ class WebContents : public TabContents, return render_manager_.interstitial_page(); } + // Find in Page -------------------------------------------------------------- + + // Starts the Find operation by calling StartFinding on the Tab. This function + // can be called from the outside as a result of hot-keys, so it uses the + // last remembered search string as specified with set_find_string(). This + // function does not block while a search is in progress. The controller will + // receive the results through the notification mechanism. See Observe(...) + // for details. + void StartFinding(const std::wstring& find_text, bool forward_direction); + + // Stops the current Find operation. If |clear_selection| is true, it will + // also clear the selection on the focused frame. + void StopFinding(bool clear_selection); + + // Accessors/Setters for find_ui_active_. + bool find_ui_active() const { return find_ui_active_; } + void set_find_ui_active(bool find_ui_active) { + find_ui_active_ = find_ui_active; + } + + // Used _only_ by testing to set the current request ID, since it calls + // StartFinding on the RenderViewHost directly, rather than by using + // StartFinding's more limited API. + void set_current_find_request_id(int current_find_request_id) { + current_find_request_id_ = current_find_request_id; + } + + // Accessor for find_text_. Used to determine if this WebContents has any + // active searches. + std::wstring find_text() const { return find_text_; } + + // Accessor for find_result_. + const FindNotificationDetails& find_result() const { return find_result_; } + // Misc state & callbacks ---------------------------------------------------- // Set whether the contents should block javascript message boxes or not. @@ -346,6 +381,11 @@ class WebContents : public TabContents, int32 page_id, const webkit_glue::WebApplicationInfo& info); virtual void OnEnterOrSpace(); + virtual void OnFindReply(int request_id, + int number_of_matches, + const gfx::Rect& selection_rect, + int active_match_ordinal, + bool final_update); virtual bool CanTerminate() const; @@ -589,6 +629,32 @@ class WebContents : public TabContents, net::LoadState load_state_; std::wstring load_state_host_; + // True if the Find UI is active for this Tab. + bool find_ui_active_; + + // True if a Find operation was aborted. This can happen if the Find box is + // closed or if the search term inside the Find box is erased while a search + // is in progress. + bool find_op_aborted_; + + // Each time a search request comes in we assign it an id before passing it + // over the IPC so that when the results come in we can evaluate whether we + // still care about the results of the search (in some cases we don't because + // the user has issued a new search). + static int find_request_id_counter_; + + // This variable keeps track of what the most recent request id is. + int current_find_request_id_; + + // The last string we searched for. This is used to figure out if this is a + // Find or a FindNext operation (FindNext should not increase the request id). + std::wstring find_text_; + + // The last find result. This object contains details about the number of + // matches, the find selection rectangle, etc. The UI can access this + // information to build its presentation. + FindNotificationDetails find_result_; + DISALLOW_COPY_AND_ASSIGN(WebContents); }; diff --git a/chrome/browser/tab_contents/web_contents_view.h b/chrome/browser/tab_contents/web_contents_view.h index 4bf8dca..1a8b4f6 100644 --- a/chrome/browser/tab_contents/web_contents_view.h +++ b/chrome/browser/tab_contents/web_contents_view.h @@ -108,47 +108,6 @@ class WebContentsView : public RenderViewHostDelegate::View { // RenderWidgetHost is deleted. Removes |host| from internal maps. void RenderWidgetHostDestroyed(RenderWidgetHost* host); - // Find in page -------------------------------------------------------------- - - // Opens the find in page window if it isn't already open. It will advance to - // the next match if |find_next| is set and there is a search string, - // otherwise, the find window will merely be opened. |forward_direction| - // indicates the direction to search when find_next is set, otherwise it is - // ignored. - virtual void FindInPage(const Browser& browser, - bool find_next, bool forward_direction) = 0; - - // Hides the find bar if there is one shown. Does nothing otherwise. The find - // bar will not be deleted, merely hidden. This ensures that any search terms - // are preserved if the user subsequently opens the find bar. - // - // If |end_session| is true, then the find session will be ended, which - // indicates the user requested they no longer be in find mode for that tab. - // The find bar will not be restored when we switch back to the tab. - // Otherwise, we assume that the find bar is being hidden because the tab is - // being hidden, and all state like visibility and tickmarks will be restored - // when the tab comes back. - virtual void HideFindBar(bool end_session) = 0; - -#if defined(OS_WIN) - // Called when the tab is reparented to a new browser window. On MS Windows, - // we have to change the parent of our find bar to go with the new window. - // - // TODO(brettw) this seems like it could be improved. Possibly all doohickies - // around the tab like this, the download bar etc. should be managed by the - // BrowserView2 object. - virtual void ReparentFindWindow(Browser* new_browser) const = 0; -#endif - - // Computes the location of the find bar and whether it is fully visible in - // its parent window. The return value indicates if the window is visible at - // all. Both out arguments are required. - // - // This is used for UI tests of the find bar. If the find bar is not currently - // shown (return value of false), the out params will be {(0, 0), false}. - virtual bool GetFindBarWindowInfo(gfx::Point* position, - bool* fully_visible) const = 0; - protected: WebContentsView() {} // Abstract interface. diff --git a/chrome/browser/tab_contents/web_contents_view_win.cc b/chrome/browser/tab_contents/web_contents_view_win.cc index 9728ec8..52989e4 100644 --- a/chrome/browser/tab_contents/web_contents_view_win.cc +++ b/chrome/browser/tab_contents/web_contents_view_win.cc @@ -7,7 +7,7 @@ #include <windows.h> #include "chrome/browser/bookmarks/bookmark_drag_data.h" -#include "chrome/browser/browser.h" // TODO(beng): this dependency is awful. +#include "chrome/browser/browser.h" // TODO(beng): this dependency is awful. #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_request_manager.h" #include "chrome/browser/renderer_host/render_process_host.h" @@ -20,7 +20,6 @@ #include "chrome/browser/tab_contents/web_contents.h" #include "chrome/browser/tab_contents/web_drag_source.h" #include "chrome/browser/tab_contents/web_drop_target.h" -#include "chrome/browser/views/find_bar_win.h" #include "chrome/browser/views/sad_tab_view.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/os_exchange_data.h" @@ -180,10 +179,6 @@ void WebContentsViewWin::OnContentsDestroy() { // automatically. The detached plugin windows will get cleaned up in proper // sequence as part of the usual cleanup when the plugin instance goes away. EnumChildWindows(GetHWND(), DetachPluginWindowsCallback, NULL); - - // Close the find bar if any. - if (find_bar_.get()) - find_bar_->Close(); } void WebContentsViewWin::OnDestroy() { @@ -216,52 +211,6 @@ void WebContentsViewWin::SizeContents(const gfx::Size& size) { WasSized(size); } -void WebContentsViewWin::FindInPage(const Browser& browser, - bool find_next, bool forward_direction) { - if (!find_bar_.get()) { - // We want the Chrome top-level (Frame) window. - HWND hwnd = reinterpret_cast<HWND>(browser.window()->GetNativeHandle()); - find_bar_.reset(new FindBarWin(this, hwnd)); - } else { - find_bar_->Show(); - } - - if (find_next && !find_bar_->find_string().empty()) - find_bar_->StartFinding(forward_direction); -} - -void WebContentsViewWin::HideFindBar(bool end_session) { - if (find_bar_.get()) { - if (end_session) - find_bar_->EndFindSession(); - else - find_bar_->DidBecomeUnselected(); - } -} - -void WebContentsViewWin::ReparentFindWindow(Browser* new_browser) const { - if (find_bar_.get()) { - find_bar_->SetParent( - reinterpret_cast<HWND>(new_browser->window()->GetNativeHandle())); - } -} - -bool WebContentsViewWin::GetFindBarWindowInfo(gfx::Point* position, - bool* fully_visible) const { - CRect window_rect; - if (!find_bar_.get() || - !::IsWindow(find_bar_->GetHWND()) || - !::GetWindowRect(find_bar_->GetHWND(), &window_rect)) { - *position = gfx::Point(0, 0); - *fully_visible = false; - return false; - } - - *position = gfx::Point(window_rect.TopLeft().x, window_rect.TopLeft().y); - *fully_visible = find_bar_->IsVisible() && !find_bar_->IsAnimating(); - return true; -} - void WebContentsViewWin::UpdateDragCursor(bool is_drop_target) { drop_target_->set_is_drop_target(is_drop_target); } @@ -326,17 +275,6 @@ void WebContentsViewWin::HandleKeyboardEvent(const WebKeyboardEvent& event) { event.actual_message.lParam); } -void WebContentsViewWin::OnFindReply(int request_id, - int number_of_matches, - const gfx::Rect& selection_rect, - int active_match_ordinal, - bool final_update) { - if (find_bar_.get()) { - find_bar_->OnFindReply(request_id, number_of_matches, selection_rect, - active_match_ordinal, final_update); - } -} - void WebContentsViewWin::ShowContextMenu(const ContextMenuParams& params) { RenderViewContextMenuController menu_controller(web_contents_, params); RenderViewContextMenu menu(&menu_controller, @@ -568,10 +506,6 @@ void WebContentsViewWin::OnWindowPosChanged(WINDOWPOS* window_pos) { // size hasn't changed. if (!(window_pos->flags & SWP_NOSIZE)) WasSized(gfx::Size(window_pos->cx, window_pos->cy)); - - // If we have a FindInPage dialog, notify it that the window changed. - if (find_bar_.get() && find_bar_->IsVisible()) - find_bar_->MoveWindowIfNecessary(gfx::Rect()); } } @@ -620,14 +554,10 @@ void WebContentsViewWin::ScrollCommon(UINT message, int scroll_type, void WebContentsViewWin::WasHidden() { web_contents_->HideContents(); - if (find_bar_.get()) - find_bar_->DidBecomeUnselected(); } void WebContentsViewWin::WasShown() { web_contents_->ShowContents(); - if (find_bar_.get()) - find_bar_->DidBecomeSelected(); } void WebContentsViewWin::WasSized(const gfx::Size& size) { @@ -635,8 +565,6 @@ void WebContentsViewWin::WasSized(const gfx::Size& size) { web_contents_->interstitial_page()->SetSize(size); if (web_contents_->render_widget_host_view()) web_contents_->render_widget_host_view()->SetSize(size); - if (find_bar_.get()) - find_bar_->RespondToResize(size); // TODO(brettw) this function can probably be moved to this class. web_contents_->RepositionSupressedPopupsToFit(size); diff --git a/chrome/browser/tab_contents/web_contents_view_win.h b/chrome/browser/tab_contents/web_contents_view_win.h index a8649d7..6b891cf 100644 --- a/chrome/browser/tab_contents/web_contents_view_win.h +++ b/chrome/browser/tab_contents/web_contents_view_win.h @@ -10,7 +10,6 @@ #include "chrome/browser/tab_contents/web_contents_view.h" #include "chrome/views/widget_win.h" -class FindBarWin; class SadTabView; struct WebDropData; class WebDropTarget; @@ -40,12 +39,6 @@ class WebContentsViewWin : public WebContentsView, virtual void SetPageTitle(const std::wstring& title); virtual void Invalidate(); virtual void SizeContents(const gfx::Size& size); - virtual void FindInPage(const Browser& browser, - bool find_next, bool forward_direction); - virtual void HideFindBar(bool end_session); - virtual void ReparentFindWindow(Browser* new_browser) const; - virtual bool GetFindBarWindowInfo(gfx::Point* position, - bool* fully_visible) const; // Backend implementation of RenderViewHostDelegate::View. virtual WebContents* CreateNewWindowInternal( @@ -63,11 +56,6 @@ class WebContentsViewWin : public WebContentsView, virtual void UpdateDragCursor(bool is_drop_target); virtual void TakeFocus(bool reverse); virtual void HandleKeyboardEvent(const WebKeyboardEvent& event); - virtual void OnFindReply(int request_id, - int number_of_matches, - const gfx::Rect& selection_rect, - int active_match_ordinal, - bool final_update); private: // Windows events ------------------------------------------------------------ @@ -108,10 +96,6 @@ class WebContentsViewWin : public WebContentsView, WebContents* web_contents_; - // For find in page. This may be NULL if there is no find bar, and if it is - // non-NULL, it may or may not be visible. - scoped_ptr<FindBarWin> find_bar_; - // A drop target object that handles drags over this WebContents. scoped_refptr<WebDropTarget> drop_target_; diff --git a/chrome/browser/views/find_bar_view.cc b/chrome/browser/views/find_bar_view.cc index 862a10f..5b8c2bc 100644 --- a/chrome/browser/views/find_bar_view.cc +++ b/chrome/browser/views/find_bar_view.cc @@ -7,6 +7,7 @@ #include <algorithm> #include "base/string_util.h" +#include "chrome/browser/tab_contents/web_contents.h" #include "chrome/browser/views/find_bar_win.h" #include "chrome/browser/view_ids.h" #include "chrome/common/l10n_util.h" @@ -22,8 +23,8 @@ static const int kWhiteSpaceAfterMatchCountLabel = 3; // The margins around the search field and the close button. -static const int kMarginLeftOfCloseButton = 5; -static const int kMarginRightOfCloseButton = 5; +static const int kMarginLeftOfCloseButton = 3; +static const int kMarginRightOfCloseButton = 7; static const int kMarginLeftOfFindTextField = 12; // The margins around the match count label (We add extra space so that the @@ -87,10 +88,9 @@ FindBarView::FindBarView(FindBarWin* container) find_next_button_(NULL), close_button_(NULL), animation_offset_(0), - toolbar_blend_(true), - match_count_(-1), - active_match_ordinal_(-1) { - ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + last_reported_matchcount_(0), + toolbar_blend_(true) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); find_text_ = new views::TextField(); find_text_->SetID(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD); @@ -170,70 +170,70 @@ FindBarView::FindBarView(FindBarWin* container) FindBarView::~FindBarView() { } -void FindBarView::ResetMatchCount() { - match_count_text_->SetText(std::wstring()); - ResetMatchCountBackground(); +void FindBarView::SetFindText(const std::wstring& find_text) { + find_text_->SetText(find_text); } -void FindBarView::ResetMatchCountBackground() { - match_count_text_->set_background( - views::Background::CreateSolidBackground(kBackgroundColorMatch)); - match_count_text_->SetColor(kTextColorMatchCount); -} - -void FindBarView::UpdateMatchCount(int number_of_matches, - bool final_update) { - if (number_of_matches < 0) // We ignore -1 sent during FindNext operations. - return; - - // If we have previously recorded a match-count number we don't want to - // overwrite it with a preliminary number of 1 (which the renderer sends when - // it found one match and is about to start scoping to find more). This way - // updates are smoother (as we don't flash '1' briefly after typing each - // letter of a query). - if (match_count_ > 0 && number_of_matches == 1 && !final_update) - return; - - if (number_of_matches == 0) - active_match_ordinal_ = 0; - - match_count_ = number_of_matches; - - if (find_text_->GetText().empty() || number_of_matches > 0) { - ResetMatchCountBackground(); - } else { - match_count_text_->set_background( - views::Background::CreateSolidBackground(kBackgroundColorNoMatch)); - match_count_text_->SetColor(kTextColorNoMatch); - MessageBeep(MB_OK); +void FindBarView::UpdateForResult(const FindNotificationDetails& result, + const std::wstring& find_text) { + bool have_valid_range = + result.number_of_matches() != -1 && result.active_match_ordinal() != -1; + + // Avoid bug 894389: When a new search starts (and finds something) it reports + // an interim match count result of 1 before the scoping effort starts. This + // is to provide feedback as early as possible that we will find something. + // As you add letters to the search term, this creates a flashing effect when + // we briefly show "1 of 1" matches because there is a slight delay until + // the scoping effort starts updating the match count. We avoid this flash by + // ignoring interim results of 1 if we already have a positive number. + if (result.number_of_matches() > -1) { + if (last_reported_matchcount_ > 0 && + result.number_of_matches() == 1 && + !result.final_update()) + return; // Don't let interim result override match count. + last_reported_matchcount_ = result.number_of_matches(); } -} -void FindBarView::UpdateActiveMatchOrdinal(int ordinal) { - if (ordinal >= 0) - active_match_ordinal_ = ordinal; -} + // If we don't have any results and something was passed in, then that means + // someone pressed F3 while the Find box was closed. In that case we need to + // repopulate the Find box with what was passed in. + if (find_text_->GetText().empty() && !find_text.empty()) { + find_text_->SetText(find_text); + find_text_->SelectAll(); + } -void FindBarView::UpdateResultLabel() { std::wstring search_string = find_text_->GetText(); - - if (search_string.length() > 0) { + if (search_string.length() > 0 && have_valid_range) { match_count_text_->SetText( l10n_util::GetStringF(IDS_FIND_IN_PAGE_COUNT, - IntToWString(active_match_ordinal_), - IntToWString(match_count_))); + IntToWString(result.active_match_ordinal()), + IntToWString(result.number_of_matches()))); } else { - ResetMatchCount(); + // If there was no text entered, we don't show anything in the result count + // area. + match_count_text_->SetText(std::wstring()); + } + + if (search_string.empty() || result.number_of_matches() > 0) { + // If there was no text entered or there were results, the match_count label + // should have a normal background color. + ResetMatchCountBackground(); + } else if (result.final_update()) { + // Otherwise we show an error background behind the match_count label. + match_count_text_->set_background( + views::Background::CreateSolidBackground(kBackgroundColorNoMatch)); + match_count_text_->SetColor(kTextColorNoMatch); + MessageBeep(MB_OK); } // Make sure Find Next and Find Previous are enabled if we found any matches. - find_previous_button_->SetEnabled(match_count_ > 0); - find_next_button_->SetEnabled(match_count_ > 0); + find_previous_button_->SetEnabled(result.number_of_matches() > 0); + find_next_button_->SetEnabled(result.number_of_matches() > 0); Layout(); // The match_count label may have increased/decreased in size. } -void FindBarView::OnShow() { +void FindBarView::SetFocusAndSelection() { find_text_->RequestFocus(); find_text_->SelectAll(); } @@ -259,11 +259,7 @@ void FindBarView::Paint(ChromeCanvas* canvas) { const SkBitmap *bg_right = toolbar_blend_ ? kDlgBackground_right : kDlgBackground_bb_right; - canvas->TileImageInt(*bg_left, - 0, - 0, - bg_left->width(), - bg_left->height()); + canvas->DrawBitmapInt(*bg_left, 0, 0); // Stretch the middle background to cover all of the area between the two // other images. @@ -275,11 +271,7 @@ void FindBarView::Paint(ChromeCanvas* canvas) { bg_right->width(), bg_middle->height()); - canvas->TileImageInt(*bg_right, - lb.right() - bg_right->width(), - 0, - bg_right->width(), - bg_right->height()); + canvas->DrawBitmapInt(*bg_right, lb.right() - bg_right->width(), 0); // Then we draw the background image for the Find TextField. We start by // calculating the position of background images for the Find text box. @@ -386,7 +378,6 @@ void FindBarView::Layout() { sz.width(), sz.height()); find_text_->SetController(this); - find_text_->RequestFocus(); // The focus forwarder view is a hidden view that should cover the area // between the find text box and the find button so that when the user clicks @@ -430,8 +421,9 @@ void FindBarView::ButtonPressed(views::BaseButton* sender) { case FIND_PREVIOUS_TAG: case FIND_NEXT_TAG: if (find_text_->GetText().length() > 0) { - container_->set_find_string(find_text_->GetText()); - container_->StartFinding(sender->GetTag() == FIND_NEXT_TAG); + container_->web_contents()->StartFinding( + find_text_->GetText(), + sender->GetTag() == FIND_NEXT_TAG); } break; case CLOSE_TAG: @@ -452,14 +444,13 @@ void FindBarView::ContentsChanged(views::TextField* sender, // if the textbox contains something we set it as the new search string and // initiate search (even though old searches might be in progress). if (new_contents.length() > 0) { - container_->set_find_string(new_contents); - container_->StartFinding(true); + container_->web_contents()->StartFinding(new_contents, true); } else { // The textbox is empty so we reset. - UpdateMatchCount(0, true); // true = final update. - UpdateResultLabel(); - container_->StopFinding(true); // true = clear selection on page. - container_->set_find_string(std::wstring()); + container_->web_contents()->StopFinding(true); // true = clear selection on + // page. + UpdateForResult(container_->web_contents()->find_result(), + std::wstring()); } } @@ -474,15 +465,22 @@ void FindBarView::HandleKeystroke(views::TextField* sender, UINT message, // Pressing Return/Enter starts the search (unless text box is empty). std::wstring find_string = find_text_->GetText(); if (find_string.length() > 0) { - container_->set_find_string(find_string); // Search forwards for enter, backwards for shift-enter. - container_->StartFinding(GetKeyState(VK_SHIFT) >= 0); + container_->web_contents()->StartFinding( + find_string, + GetKeyState(VK_SHIFT) >= 0); } break; } } } +void FindBarView::ResetMatchCountBackground() { + match_count_text_->set_background( + views::Background::CreateSolidBackground(kBackgroundColorMatch)); + match_count_text_->SetColor(kTextColorMatchCount); +} + bool FindBarView::FocusForwarderView::OnMousePressed( const views::MouseEvent& event) { if (view_to_focus_on_mousedown_) { @@ -491,4 +489,3 @@ bool FindBarView::FocusForwarderView::OnMousePressed( } return true; } - diff --git a/chrome/browser/views/find_bar_view.h b/chrome/browser/views/find_bar_view.h index 146f96b..2818d6d 100644 --- a/chrome/browser/views/find_bar_view.h +++ b/chrome/browser/views/find_bar_view.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_VIEWS_FIND_BAR_VIEW_H_ #include "base/gfx/size.h" +#include "chrome/browser/find_notification_details.h" #include "chrome/views/button.h" #include "chrome/views/text_field.h" @@ -35,31 +36,19 @@ class FindBarView : public views::View, CLOSE_TAG, // The Close button (the 'X'). }; - FindBarView(FindBarWin* container); + explicit FindBarView(FindBarWin* container); virtual ~FindBarView(); - // Updates the UI to show how many matches were found on the page/frames. - // This function does nothing if |number_of_matches| is below 0, which can - // happen during a FindNext operation when a scoping effort is already in - // progress. |final_update| specifies whether this is the last update message - // this Find operation will produce or if this is just a preliminary report. - void UpdateMatchCount(int number_of_matches, bool final_update); - - // Notifies the view of the ordinal for the currently active item on the page. - void UpdateActiveMatchOrdinal(int ordinal); + // Sets the text displayed in the text box. + void SetFindText(const std::wstring& find_text); // Updates the label inside the Find text box that shows the ordinal of the // active item and how many matches were found. - void UpdateResultLabel(); - - // Resets the UI element that shows how many matches were found. - void ResetMatchCount(); - - // Resets the background for the match count label. - void ResetMatchCountBackground(); + void UpdateForResult(const FindNotificationDetails& result, + const std::wstring& find_text); - // View needs to respond to Show to set focus to the find text box - void OnShow(); + // Claims focus for the text field and selects its contents. + void SetFocusAndSelection(); // Updates the view to let it know where the controller is clipping the // Find window (while animating the opening or closing of the window). @@ -81,9 +70,12 @@ class FindBarView : public views::View, TCHAR key, UINT repeat_count, UINT flags); // Set whether or not we're attempting to blend with the toolbar. - void SetToolbarBlend(bool toolbar_blend) {toolbar_blend_ = toolbar_blend;} + void set_toolbar_blend(bool toolbar_blend) { toolbar_blend_ = toolbar_blend; } private: + // Resets the background for the match count label. + void ResetMatchCountBackground(); + // We use a hidden view to grab mouse clicks and bring focus to the find // text box. This is because although the find text box may look like it // extends all the way to the find button, it only goes as far as to the @@ -116,6 +108,9 @@ class FindBarView : public views::View, views::Button* find_next_button_; views::Button* close_button_; + // The last matchcount number we reported to the user. + int last_reported_matchcount_; + // Whether or not we're attempting to blend with the toolbar (this is // false if the bookmarks bar is visible). bool toolbar_blend_; @@ -126,12 +121,6 @@ class FindBarView : public views::View, // in the right location. int animation_offset_; - // How many matches were found on the page. - int match_count_; - - // The ordinal of the currently active match. - int active_match_ordinal_; - DISALLOW_COPY_AND_ASSIGN(FindBarView); }; diff --git a/chrome/browser/views/find_bar_win.cc b/chrome/browser/views/find_bar_win.cc index 671cc92..9ab7f1d 100644 --- a/chrome/browser/views/find_bar_win.cc +++ b/chrome/browser/views/find_bar_win.cc @@ -6,11 +6,12 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/find_notification_details.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/bookmark_bar_view.h" #include "chrome/browser/views/find_bar_view.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/web_contents.h" #include "chrome/browser/tab_contents/web_contents_view.h" #include "chrome/common/notification_service.h" @@ -20,25 +21,20 @@ #include "chrome/views/view_storage.h" #include "chrome/views/widget_win.h" -int FindBarWin::request_id_counter_ = 0; - // The minimum space between the FindInPage window and the search result. static const int kMinFindWndDistanceFromSelection = 5; -// The amount of space we expect the window border to take up. -static const int kWindowBorderWidth = 3; - //////////////////////////////////////////////////////////////////////////////// // FindBarWin, public: -FindBarWin::FindBarWin(WebContentsView* parent_tab, HWND parent_hwnd) - : parent_tab_(parent_tab), - current_request_id_(request_id_counter_++), - parent_hwnd_(parent_hwnd), +FindBarWin::FindBarWin(BrowserView* browser_view) + : web_contents_(NULL), + browser_view_(browser_view), find_dialog_animation_offset_(0), - show_on_tab_selection_(false), focus_manager_(NULL), old_accel_target_for_esc_(NULL) { + HWND parent_hwnd = browser_view->GetWidget()->GetHWND(); + // Start listening to focus changes, so we can register and unregister our // own handler for Escape. SetFocusChangeListener(parent_hwnd); @@ -49,36 +45,38 @@ FindBarWin::FindBarWin(WebContentsView* parent_tab, HWND parent_hwnd) view_ = new FindBarView(this); - views::FocusManager* focus_manager; - focus_manager = views::FocusManager::GetFocusManager(parent_hwnd_); + views::FocusManager* focus_manager = views::FocusManager::GetFocusManager( + parent_hwnd); DCHECK(focus_manager); // Stores the currently focused view, and tracks focus changes so that we can // restore focus when the find box is closed. focus_tracker_.reset(new views::ExternalFocusTracker(view_, focus_manager)); - // Figure out where to place the dialog, initialize and set the position. - gfx::Rect find_dlg_rect = GetDialogPosition(gfx::Rect()); + // Initialize the native window. set_window_style(WS_CHILD | WS_CLIPCHILDREN); set_window_ex_style(WS_EX_TOPMOST); - WidgetWin::Init(parent_hwnd, find_dlg_rect, false); + WidgetWin::Init(parent_hwnd, gfx::Rect(), false); SetContentsView(view_); // Start the process of animating the opening of the window. animation_.reset(new SlideAnimation(this)); - animation_->Show(); } FindBarWin::~FindBarWin() { - Close(); } // TODO(brettw) this should not be so complicated. The view should really be in // charge of these regions. CustomFrameWindow will do this for us. It will also // let us set a path for the window region which will avoid some logic here. void FindBarWin::UpdateWindowEdges(const gfx::Rect& new_pos) { - int w = new_pos.width(); - int h = new_pos.height(); + // |w| is used to make it easier to create the part of the polygon that curves + // the right side of the Find window. It essentially keeps track of the + // x-pixel position of the right-most background image inside the view. + // TODO(finnur): Let the view tell us how to draw the curves or convert + // this to a CustomFrameWindow. + int w = new_pos.width() - 6; // -6 positions us at the left edge of the + // rightmost background image of the view. // This polygon array represents the outline of the background image for the // dialog. Basically, it encompasses only the visible pixels of the @@ -150,8 +148,8 @@ void FindBarWin::UpdateWindowEdges(const gfx::Rect& new_pos) { // // TODO(brettw) this constant is evil. This is the amount of room we've added // to the window size, when we set the region, it can change the size. - static const int kAddedWidth = 14; - int difference = (curr_pos_relative_.right() - kAddedWidth) - + static const int kAddedWidth = 7; + int difference = (new_pos.right() - kAddedWidth) - dialog_bounds.width() - views::NativeScrollBar::GetVerticalScrollBarWidth() + 1; @@ -180,26 +178,14 @@ void FindBarWin::UpdateWindowEdges(const gfx::Rect& new_pos) { } void FindBarWin::Show() { - // Note: This function is called when the user presses Ctrl+F or switches back - // to the parent tab of the Find window (assuming the Find window has been - // opened at least once). If the Find window is already visible, we should - // just forward the command to the view so that it will select all text and - // grab focus. If the window is not visible, however, there are two scenarios: - if (!IsVisible() && !animation_->IsAnimating()) { - if (show_on_tab_selection_) { - // The tab just got re-selected and we need to show the window again - // (without animation). We also want to reset the window location so that - // we don't surprise the user by popping up to the left for no apparent - // reason. - gfx::Rect new_pos = GetDialogPosition(gfx::Rect()); - SetDialogPosition(new_pos); - } else { - // The Find window was dismissed and we need to start the animation again. - animation_->Show(); - } + // Only show the animation if we're not already showing a find bar for the + // selected WebContents. + if (!web_contents_->find_ui_active()) { + web_contents_->set_find_ui_active(true); + animation_->Reset(); + animation_->Show(); } - - view_->OnShow(); + view_->SetFocusAndSelection(); } bool FindBarWin::IsAnimating() { @@ -207,122 +193,115 @@ bool FindBarWin::IsAnimating() { } void FindBarWin::EndFindSession() { - if (IsVisible()) { - show_on_tab_selection_ = false; - animation_->Hide(); - - // We reset the match count here so that we don't show old results when the - // user has navigated to another page. We could alternatively achieve the - // same effect by nulling the search string, but then the user looses the - // last search that was entered, which can be frustrating if searching for - // the same string on multiple pages. - view_->ResetMatchCount(); - - // When we hide the window, we need to notify the renderer that we are done - // for now, so that we can abort the scoping effort and clear all the - // tick-marks and highlighting. - StopFinding(false); // false = don't clear selection on page. - - // When we get dismissed we restore the focus to where it belongs. - RestoreSavedFocus(); - } -} - -void FindBarWin::Close() { - // We may already have been destroyed if the selection resulted in a tab - // switch which will have reactivated the browser window and closed us, so - // we need to check to see if we're still a window before trying to destroy - // ourself. - if (IsWindow()) - DestroyWindow(); + animation_->Reset(1.0); + animation_->Hide(); + + // When we hide the window, we need to notify the renderer that we are done + // for now, so that we can abort the scoping effort and clear all the + // tickmarks and highlighting. + web_contents_->StopFinding(false); // false = don't clear selection on + // page. + view_->UpdateForResult(web_contents_->find_result(), std::wstring()); + + // When we get dismissed we restore the focus to where it belongs. + RestoreSavedFocus(); } -void FindBarWin::DidBecomeSelected() { - if (!IsVisible() && show_on_tab_selection_) { - Show(); - show_on_tab_selection_ = false; +void FindBarWin::ChangeWebContents(WebContents* contents) { + if (web_contents_) { + NotificationService::current()->RemoveObserver( + this, NotificationType::FIND_RESULT_AVAILABLE, + Source<TabContents>(web_contents_)); + NotificationService::current()->RemoveObserver( + this, NotificationType::NAV_ENTRY_COMMITTED, + Source<NavigationController>(web_contents_->controller())); + if (animation_->IsAnimating()) + animation_->End(); } -} -void FindBarWin::DidBecomeUnselected() { - if (::IsWindow(GetHWND()) && IsVisible()) { - // Finish any existing animations. - if (animation_->IsAnimating()) { - show_on_tab_selection_ = animation_->IsShowing(); - animation_->End(); - } else { - show_on_tab_selection_ = true; + web_contents_ = contents; + + if (web_contents_) { + if (IsVisible() && web_contents_ && !web_contents_->find_ui_active()) + ShowWindow(SW_HIDE); + + NotificationService::current()->AddObserver( + this, NotificationType::FIND_RESULT_AVAILABLE, + Source<TabContents>(web_contents_)); + NotificationService::current()->AddObserver( + this, NotificationType::NAV_ENTRY_COMMITTED, + Source<NavigationController>(web_contents_->controller())); + + // Update the find bar with existing results and search text, regardless of + // whether or not the find bar is visible, so that if it's subsequently + // shown it is showing the right state for this tab. We update the find text + // _first_ since the FindBarView checks its emptiness to see if it should + // clear the result count display when there's nothing in the box. + view_->SetFindText(web_contents_->find_text()); + + if (web_contents_->find_ui_active()) { + // A tab with a visible find bar just got selected and we need to show the + // find bar but without animation since it was already animated into its + // visible state. We also want to reset the window location so that + // we don't surprise the user by popping up to the left for no apparent + // reason. + gfx::Rect new_pos = GetDialogPosition(gfx::Rect()); + SetDialogPosition(new_pos, false); + + // Only modify focus and selection if Find is active, otherwise the Find + // Bar will interfere with user input. + view_->SetFocusAndSelection(); } - ShowWindow(SW_HIDE); + UpdateUIForFindResult(web_contents_->find_result(), + web_contents_->find_text()); } } -void FindBarWin::StartFinding(bool forward_direction) { - if (find_string_.empty()) +void FindBarWin::MoveWindowIfNecessary(const gfx::Rect& selection_rect, + bool no_redraw) { + // We only move the window if one is active for the current WebContents. If we + // don't check this, then SetDialogPosition below will end up making the Find + // Bar visible. + if (!web_contents_ || !web_contents_->find_ui_active()) return; - bool find_next = last_find_string_ == find_string_; - if (!find_next) - current_request_id_ = request_id_counter_++; - - last_find_string_ = find_string_; - - GetRenderViewHost()->StartFinding(current_request_id_, - find_string_, - forward_direction, - false, // case sensitive - find_next); -} - -void FindBarWin::StopFinding(bool clear_selection) { - last_find_string_.clear(); - GetRenderViewHost()->StopFinding(clear_selection); -} - -void FindBarWin::MoveWindowIfNecessary( - const gfx::Rect& selection_rect) { gfx::Rect new_pos = GetDialogPosition(selection_rect); - SetDialogPosition(new_pos); + SetDialogPosition(new_pos, no_redraw); - // May need to redraw our frame to accomodate bookmark bar - // styles. + // May need to redraw our frame to accommodate bookmark bar styles. view_->SchedulePaint(); } -void FindBarWin::RespondToResize(const gfx::Size& new_size) { - if (!IsVisible()) - return; - - // We are only interested in changes to width. - if (window_size_.width() == new_size.width()) - return; - - // Save the new size so we can compare later and ignore future invocations - // of RespondToResize. - window_size_ = new_size; - - gfx::Rect new_pos = GetDialogPosition(gfx::Rect()); - SetDialogPosition(new_pos); -} - -void FindBarWin::SetParent(HWND new_parent) { - DCHECK(new_parent); - if (parent_hwnd_ != new_parent) { - // Sync up the focus listener with the new focus manager. - SetFocusChangeListener(new_parent); - - parent_hwnd_ = new_parent; - ::SetParent(GetHWND(), new_parent); - - // The MSDN documentation specifies that you need to manually update the - // UI state after changing the parent. - ::SendMessage(new_parent, - WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0); - - // We have a new focus manager now, so start tracking with that. - focus_tracker_.reset(new views::ExternalFocusTracker(view_, - focus_manager_)); +//////////////////////////////////////////////////////////////////////////////// +// FindBarWin, NotificationObserver implementation: + +void FindBarWin::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::FIND_RESULT_AVAILABLE) { + // Don't update for notifications from TabContentses other than the one we are + // actively tracking. + if (Source<TabContents>(source).ptr() == web_contents_) { + UpdateUIForFindResult(web_contents_->find_result(), + web_contents_->find_text()); + FindNotificationDetails details = web_contents_->find_result(); + } + } else if (type == NotificationType::NAV_ENTRY_COMMITTED) { + NavigationController* source_controller = + Source<NavigationController>(source).ptr(); + if (source_controller == web_contents_->controller()) { + NavigationController::LoadCommittedDetails* commit_details = + Details<NavigationController::LoadCommittedDetails>(details).ptr(); + PageTransition::Type transition_type = + commit_details->entry->transition_type(); + // We hide the FindInPage window when the user navigates away, except on + // reload. + if (IsVisible() && PageTransition::StripQualifier(transition_type) != + PageTransition::RELOAD) { + EndFindSession(); + } + } } } @@ -330,6 +309,9 @@ void FindBarWin::SetParent(HWND new_parent) { // FindBarWin, views::WidgetWin implementation: void FindBarWin::OnFinalMessage(HWND window) { + // TODO(beng): Destroy the RootView before destroying the Focus Manager will + // allow us to remove this method. + // We are exiting, so we no longer need to monitor focus changes. focus_manager_->RemoveFocusChangeListener(this); @@ -384,14 +366,15 @@ bool FindBarWin::AcceleratorPressed(const views::Accelerator& accelerator) { void FindBarWin::AnimationProgressed(const Animation* animation) { // First, we calculate how many pixels to slide the window. + gfx::Size pref_size = view_->GetPreferredSize(); find_dialog_animation_offset_ = static_cast<int>((1.0 - animation_->GetCurrentValue()) * - view_->height()); + pref_size.height()); // This call makes sure it appears in the right location, the size and shape // is correct and that it slides in the right direction. gfx::Rect find_dlg_rect = GetDialogPosition(gfx::Rect()); - SetDialogPosition(find_dlg_rect); + SetDialogPosition(find_dlg_rect, false); // Let the view know if we are animating, and at which offset to draw the // edges. @@ -409,125 +392,13 @@ void FindBarWin::AnimationEnded(const Animation* animation) { } } -void FindBarWin::OnFindReply(int request_id, - int number_of_matches, - const gfx::Rect& selection_rect, - int active_match_ordinal, - bool final_update) { - // Ignore responses for requests other than the one we have most recently - // issued. That way we won't act on stale results when the user has - // already typed in another query. - if (view_ && request_id == current_request_id_) { - view_->UpdateMatchCount(number_of_matches, final_update); - view_->UpdateActiveMatchOrdinal(active_match_ordinal); - view_->UpdateResultLabel(); - - // We now need to check if the window is obscuring the search results. - if (!selection_rect.IsEmpty()) - MoveWindowIfNecessary(selection_rect); - - // Once we find a match we no longer want to keep track of what had - // focus. EndFindSession will then set the focus to the page content. - if (number_of_matches > 0) - focus_tracker_.reset(NULL); - } - - // Notify all observers of this notification, such as the automation - // providers which do UI tests for find in page. - FindNotificationDetails detail(request_id, - number_of_matches, - selection_rect, - active_match_ordinal, - final_update); - NotificationService::current()->Notify( - NotificationType::FIND_RESULT_AVAILABLE, - Source<TabContents>(parent_tab_->GetWebContents()), - Details<FindNotificationDetails>(&detail)); -} - -RenderViewHost* FindBarWin::GetRenderViewHost() const { - return parent_tab_->GetWebContents()->render_view_host(); -} - void FindBarWin::GetDialogBounds(gfx::Rect* bounds) { DCHECK(bounds); - - // We need to find the View for the toolbar because we want to visually - // extend it (draw our dialog slightly overlapping its border). - views::View* root_view = views::GetRootViewForHWND(parent_hwnd_); - views::View* toolbar = NULL; - BookmarkBarView* bookmark_bar = NULL; - if (root_view) { - toolbar = root_view->GetViewByID(VIEW_ID_TOOLBAR); - bookmark_bar = static_cast<BookmarkBarView*>( - root_view->GetViewByID(VIEW_ID_BOOKMARK_BAR)); - } - - // To figure out what area we have to work with we need to know the rect for - // the browser window and the page content area starts and get a pointer to - // the toolbar to see where to draw the FindInPage dialog. If any of this - // fails, we return an empty rect. - CRect browser_client_rect, browser_window_rect, content_window_rect; - if (!::IsWindow(parent_hwnd_) || - !::GetWindowRect(parent_tab_->GetContentNativeView(), - &content_window_rect) || - !::GetWindowRect(parent_hwnd_, &browser_window_rect) || - !::GetClientRect(parent_hwnd_, &browser_client_rect) || - !toolbar) { - *bounds = gfx::Rect(); - return; - } - - // Start with browser's client rect, then change it below. - *bounds = gfx::Rect(browser_client_rect); - - // Find the bounds of the toolbar we want to dock to. - gfx::Rect toolbar_bounds; - views::View* bounds_view = NULL; - view_->SetToolbarBlend(true); - if (bookmark_bar && !bookmark_bar->IsDetachedStyle()) { - bounds_view = bookmark_bar; - toolbar_bounds = bookmark_bar->GetLocalBounds(false); - if (bookmark_bar->IsAlwaysShown()) - view_->SetToolbarBlend(false); - } else if (toolbar) { - bounds_view = toolbar; - toolbar_bounds = toolbar->GetLocalBounds(false); - } - - // Figure out at which y coordinate to draw the FindInPage window. If we have - // a toolbar (chrome) we want to overlap it by one pixel so that we look like - // we are part of the chrome (which will also draw our window on top of any - // info-bars, if present). If there is no chrome, then we have a constrained - // window or a Chrome application so we want to draw at the top of the page - // content (right beneath the title bar). - int y_pos_offset = 0; - if (bounds_view) { - // We have a toolbar (chrome), so overlap it by one pixel. - gfx::Point origin; - views::View::ConvertPointToWidget(bounds_view, &origin); - toolbar_bounds.Offset(origin); - y_pos_offset = toolbar_bounds.bottom() - 1; - } else { - // The toolbar isn't visible, so we're in fullscreen mode or this is an app - // window. This means we draw the Find window at the top of the page content - // window. We subtract 1 to overlap the client edge that is part of the - // title bar (so that we don't look detached by 1 pixel). - // TODO(pkasting): This -1 is wrong in maximized mode. - WINDOWINFO wi; - wi.cbSize = sizeof(WINDOWINFO); - GetWindowInfo(parent_hwnd_, &wi); - y_pos_offset = content_window_rect.TopLeft().y - wi.rcClient.top - 1; - } - - bounds->Offset(0, y_pos_offset); - - // We also want to stay well within limits of the vertical scrollbar and not - // draw on the window border (frame) itself either. - int width = views::NativeScrollBar::GetVerticalScrollBarWidth(); - width += kWindowBorderWidth; - bounds->set_x(bounds->x() + width); - bounds->set_width(bounds->width() - (2 * width)); + // The BrowserView does Layout for the components that we care about + // positioning relative to, so we ask it to tell us where we should go. + *bounds = browser_view_->GetFindBarBoundingBox(); + view_->set_toolbar_blend( + !browser_view_->ShouldFindBarBlendWithBookmarksBar()); } gfx::Rect FindBarWin::GetDialogPosition(gfx::Rect avoid_overlapping_rect) { @@ -567,8 +438,8 @@ gfx::Rect FindBarWin::GetDialogPosition(gfx::Rect avoid_overlapping_rect) { // for the fact that we draw the Find dialog relative to the window, // whereas the selection rect is relative to the page. RECT frame_rect = {0}, webcontents_rect = {0}; - ::GetWindowRect(parent_hwnd_, &frame_rect); - ::GetWindowRect(parent_tab_->GetNativeView(), &webcontents_rect); + ::GetWindowRect(GetParent(), &frame_rect); + ::GetWindowRect(web_contents_->view()->GetNativeView(), &webcontents_rect); avoid_overlapping_rect.Offset(0, webcontents_rect.top - frame_rect.top); } @@ -603,7 +474,7 @@ gfx::Rect FindBarWin::GetDialogPosition(gfx::Rect avoid_overlapping_rect) { return new_pos; } -void FindBarWin::SetDialogPosition(const gfx::Rect& new_pos) { +void FindBarWin::SetDialogPosition(const gfx::Rect& new_pos, bool no_redraw) { if (new_pos.IsEmpty()) return; @@ -612,11 +483,18 @@ void FindBarWin::SetDialogPosition(const gfx::Rect& new_pos) { // of it it doesn't look like the window crumbles into the toolbar. UpdateWindowEdges(new_pos); - ::SetWindowPos(GetHWND(), HWND_TOP, - new_pos.x(), new_pos.y(), new_pos.width(), new_pos.height(), - SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_SHOWWINDOW); + CRect window_rect; + GetWindowRect(&window_rect); + DWORD swp_flags = SWP_NOOWNERZORDER; + if (!window_rect.IsRectEmpty()) + swp_flags |= SWP_NOSIZE; + if (no_redraw) + swp_flags |= SWP_NOREDRAW; + if (!IsVisible()) + swp_flags |= SWP_SHOWWINDOW; - curr_pos_relative_ = new_pos; + ::SetWindowPos(GetHWND(), HWND_TOP, new_pos.x(), new_pos.y(), new_pos.width(), + new_pos.height(), swp_flags); } void FindBarWin::SetFocusChangeListener(HWND parent_hwnd) { @@ -638,7 +516,7 @@ void FindBarWin::SetFocusChangeListener(HWND parent_hwnd) { void FindBarWin::RestoreSavedFocus() { if (focus_tracker_.get() == NULL) { // TODO(brettw) Focus() should be on WebContentsView. - parent_tab_->GetWebContents()->Focus(); + web_contents_->Focus(); } else { focus_tracker_->FocusLastFocusedExternalView(); } @@ -667,3 +545,16 @@ void FindBarWin::UnregisterEscAccelerator() { focus_manager_->RegisterAccelerator(escape, old_accel_target_for_esc_); } +void FindBarWin::UpdateUIForFindResult(const FindNotificationDetails& result, + const std::wstring& find_text) { + view_->UpdateForResult(result, find_text); + + // We now need to check if the window is obscuring the search results. + if (!result.selection_rect().IsEmpty()) + MoveWindowIfNecessary(result.selection_rect(), false); + + // Once we find a match we no longer want to keep track of what had + // focus. EndFindSession will then set the focus to the page content. + if (result.number_of_matches() > 0) + focus_tracker_.reset(NULL); +} diff --git a/chrome/browser/views/find_bar_win.h b/chrome/browser/views/find_bar_win.h index f1727de..c226ea9 100644 --- a/chrome/browser/views/find_bar_win.h +++ b/chrome/browser/views/find_bar_win.h @@ -6,14 +6,16 @@ #define CHROME_BROWSER_VIEWS_FIND_BAR_WIN_H_ #include "base/gfx/rect.h" +#include "chrome/browser/find_notification_details.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/common/animation.h" +#include "chrome/common/notification_service.h" #include "chrome/views/widget_win.h" +class BrowserView; class FindBarView; class RenderViewHost; class SlideAnimation; -class WebContentsView; namespace views { class ExternalFocusTracker; @@ -26,60 +28,43 @@ class View; // functionality. It uses the FindBarWin implementation to draw its content and // is responsible for showing, hiding, closing, and moving the window if needed, // for example if the window is obscuring the selection results. It also -// communicates with the parent_tab to instruct it to start searching for what -// the user selected and receives notifications about the search results and -// communicates that to the view. +// receives notifications about the search results and communicates that to the +// view. // -// We create one container per tab and remember each search query per tab. +// There is one FindBarWin per BrowserView, and its state is updated whenever +// the selected Tab is changed. The FindBarWin is created when the BrowserView +// is attached to the frame's Widget for the first time. // //////////////////////////////////////////////////////////////////////////////// class FindBarWin : public views::FocusChangeListener, public views::WidgetWin, - public AnimationDelegate { + public AnimationDelegate, + public NotificationObserver { public: - FindBarWin(WebContentsView* parent_tab, HWND parent_hwnd); + explicit FindBarWin(BrowserView* browser_view); virtual ~FindBarWin(); + // Accessor for the attached WebContents. + WebContents* web_contents() const { return web_contents_; } + // Shows the find bar. Any previous search string will again be visible. void Show(); // Ends the current session. void EndFindSession(); - // Closes the find bar window (calls Close on the Window Container). - void Close(); - - // This is triggered when the parent tab of the Find dialog becomes - // unselected, at which point the find bar should become hidden. Otherwise, - // we leave artifacts on the chrome when other tabs are visible. However, we - // need to show the Find dialog again when the parent tab becomes selected - // again, so we set a flag for that and show the window if we get a - // DidBecomeSelected call. - void DidBecomeUnselected(); - - // If |show_on_tab_selection_| is true, then we show the dialog and clear the - // flag, otherwise we do nothing. - void DidBecomeSelected(); - - // Starts the Find operation by calling StartFinding on the Tab. This function - // can be called from the outside as a result of hot-keys, so it uses the - // last remembered search string as specified with set_find_string(). This - // function does not block while a search is in progress. The controller will - // receive the results through the notification mechanism. See Observe(...) - // for details. - void StartFinding(bool forward_direction); - - // Stops the current Find operation. If |clear_selection| is true, it will - // also clear the selection on the focused frame. - void StopFinding(bool clear_selection); + // Changes the WebContents that this FindBar is attached to. This occurs when + // the user switches tabs in the Browser window. |contents| can be NULL. + void ChangeWebContents(WebContents* contents); // If the find bar obscures the search results we need to move the window. To // do that we need to know what is selected on the page. We simply calculate // where it would be if we place it on the left of the selection and if it // doesn't fit on the screen we try the right side. The parameter // |selection_rect| is expected to have coordinates relative to the top of - // the web page area. - void MoveWindowIfNecessary(const gfx::Rect& selection_rect); + // the web page area. If |no_redraw| is true, the window will be moved without + // redrawing siblings. + void MoveWindowIfNecessary(const gfx::Rect& selection_rect, bool no_redraw); // Moves the window according to the new window size. void RespondToResize(const gfx::Size& new_size); @@ -87,11 +72,6 @@ class FindBarWin : public views::FocusChangeListener, // Whether we are animating the position of the Find window. bool IsAnimating(); - // Changes the parent window for the find bar. If |new_parent| is already - // the parent of this window then no action is taken. - // |new_parent| can not be NULL. - void SetParent(HWND new_parent); - // We need to monitor focus changes so that we can register a handler for // Escape when we get focus and unregister it when we looses focus. This // function unregisters our old Escape accelerator (if registered) and @@ -99,19 +79,10 @@ class FindBarWin : public views::FocusChangeListener, // new |parent_hwnd|. void SetFocusChangeListener(HWND parent_hwnd); - // Accessors for specifying and retrieving the current search string. - std::wstring find_string() { return find_string_; } - void set_find_string(const std::wstring& find_string) { - find_string_ = find_string; - } - - // Updates the find bar with the latest results. This is called when the - // renderer (through the RenderViewHostDelegate::View) finds more stuff. - void OnFindReply(int request_id, - int number_of_matches, - const gfx::Rect& selection_rect, - int active_match_ordinal, - bool final_update); + // Overridden from NotificationObserver: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); // Overridden from views::WidgetWin: virtual void OnFinalMessage(HWND window); @@ -128,9 +99,6 @@ class FindBarWin : public views::FocusChangeListener, virtual void AnimationEnded(const Animation* animation); private: - // Returns the RenderViewHost associated with the current tab. - RenderViewHost* GetRenderViewHost() const; - // Retrieves the boundaries that the find bar has to work with within the // Chrome frame window. The resulting rectangle will be a rectangle that // overlaps the bottom of the Chrome toolbar by one pixel (so we can create @@ -159,8 +127,9 @@ class FindBarWin : public views::FocusChangeListener, // Moves the dialog window to the provided location, moves it to top in the // z-order (HWND_TOP, not HWND_TOPMOST) and shows the window (if hidden). // It then calls UpdateWindowEdges to make sure we don't overwrite the Chrome - // window border. - void SetDialogPosition(const gfx::Rect& new_pos); + // window border. If |no_redraw| is set, the window is getting moved but not + // sized, and should not be redrawn to reduce update flicker. + void SetDialogPosition(const gfx::Rect& new_pos, bool no_redraw); // The dialog needs rounded edges, so we create a polygon that corresponds to // the background images for this window (and make the polygon only contain @@ -182,46 +151,26 @@ class FindBarWin : public views::FocusChangeListener, // also: SetFocusChangeListener(). void UnregisterEscAccelerator(); - // The tab we are associated with. - WebContentsView* parent_tab_; + // Updates the FindBarView with the find result details contained within the + // specified |result|. + void UpdateUIForFindResult(const FindNotificationDetails& result, + const std::wstring& find_text); + + // The WebContents we are currently associated with. + WebContents* web_contents_; - // The window handle of our parent window (the main Chrome window). - HWND parent_hwnd_; + // The BrowserView that created us. + BrowserView* browser_view_; // Our view, which is responsible for drawing the UI. FindBarView* view_; - // Each time a search request comes in we assign it an id before passing it - // over the IPC so that when the results come in we can evaluate whether we - // still care about the results of the search (in some cases we don't because - // the user has issued a new search). - static int request_id_counter_; - - // This variable keeps track of what the most recent request id is. - int current_request_id_; - - // The current string we are searching for. - std::wstring find_string_; - - // The last string we searched for. This is used to figure out if this is a - // Find or a FindNext operation (FindNext should not increase the request id). - std::wstring last_find_string_; - - // The current window position (relative to parent). - gfx::Rect curr_pos_relative_; - - // The current window size. - gfx::Size window_size_; - // The y position pixel offset of the window while animating the Find dialog. int find_dialog_animation_offset_; // The animation class to use when opening the Find window. scoped_ptr<SlideAnimation> animation_; - // Whether to show the Find dialog when its tab becomes selected again. - bool show_on_tab_selection_; - // The focus manager we register with to keep track of focus changes. views::FocusManager* focus_manager_; diff --git a/chrome/browser/views/find_bar_win_interactive_uitest.cc b/chrome/browser/views/find_bar_win_interactive_uitest.cc index 9bb7d9c..e767506 100644 --- a/chrome/browser/views/find_bar_win_interactive_uitest.cc +++ b/chrome/browser/views/find_bar_win_interactive_uitest.cc @@ -66,13 +66,13 @@ TEST_F(FindInPageTest, CrashEscHandlers) { scoped_ptr<TabProxy> tabA(GetActiveTab()); EXPECT_NE(AUTOMATION_MSG_NAVIGATION_ERROR, tabA->NavigateToURL(url)); - EXPECT_TRUE(tabA->OpenFindInPage()); + EXPECT_TRUE(browser->OpenFindInPage()); // Open another tab (tab B). EXPECT_TRUE(browser->AppendTab(url)); scoped_ptr<TabProxy> tabB(GetActiveTab()); - EXPECT_TRUE(tabB->OpenFindInPage()); + EXPECT_TRUE(browser->OpenFindInPage()); // Select tab A. EXPECT_TRUE(ActivateTabByClick(automation(), window.get(), 0)); diff --git a/chrome/browser/views/find_bar_win_uitest.cc b/chrome/browser/views/find_bar_win_uitest.cc index 607aa14..21d2287 100644 --- a/chrome/browser/views/find_bar_win_uitest.cc +++ b/chrome/browser/views/find_bar_win_uitest.cc @@ -41,23 +41,20 @@ TEST_F(FindInPageControllerTest, FindInPageOrdinal) { int ordinal = 0; EXPECT_EQ(3, tab->FindInPage(L"o", FWD, IGNORE_CASE, false, &ordinal)); EXPECT_EQ(1, ordinal); - // FindNext returns -1 for match count because it doesn't bother with - // recounting the number of matches. We don't care about the match count - // anyway in this case, we just want to check the ordinal. - EXPECT_EQ(-1, tab->FindInPage(L"o", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(3, tab->FindInPage(L"o", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(2, ordinal); - EXPECT_EQ(-1, tab->FindInPage(L"o", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(3, tab->FindInPage(L"o", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(3, ordinal); // Go back one match. - EXPECT_EQ(-1, tab->FindInPage(L"o", BACK, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(3, tab->FindInPage(L"o", BACK, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(2, ordinal); - EXPECT_EQ(-1, tab->FindInPage(L"o", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(3, tab->FindInPage(L"o", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(3, ordinal); // This should wrap to the top. - EXPECT_EQ(-1, tab->FindInPage(L"o", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(3, tab->FindInPage(L"o", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(1, ordinal); // This should go back to the end. - EXPECT_EQ(-1, tab->FindInPage(L"o", BACK, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(3, tab->FindInPage(L"o", BACK, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(3, ordinal); } @@ -79,31 +76,28 @@ TEST_F(FindInPageControllerTest, FindInPageMultiFramesOrdinal) { int ordinal = 0; EXPECT_EQ(7, tab->FindInPage(L"a", FWD, IGNORE_CASE, false, &ordinal)); EXPECT_EQ(1, ordinal); - // FindNext returns -1 for match count because it doesn't bother with - // recounting the number of matches. We don't care about the match count - // anyway in this case, we just want to check the ordinal. - EXPECT_EQ(-1, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(2, ordinal); - EXPECT_EQ(-1, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(3, ordinal); - EXPECT_EQ(-1, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(4, ordinal); // Go back one, which should go back one frame. - EXPECT_EQ(-1, tab->FindInPage(L"a", BACK, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", BACK, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(3, ordinal); - EXPECT_EQ(-1, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(4, ordinal); - EXPECT_EQ(-1, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(5, ordinal); - EXPECT_EQ(-1, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(6, ordinal); - EXPECT_EQ(-1, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(7, ordinal); // Now we should wrap back to frame 1. - EXPECT_EQ(-1, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(1, ordinal); // Now we should wrap back to frame last frame. - EXPECT_EQ(-1, tab->FindInPage(L"a", BACK, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(7, tab->FindInPage(L"a", BACK, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(7, ordinal); } @@ -124,16 +118,13 @@ TEST_F(FindInPageControllerTest, FindInPage_Issue5132) { int ordinal = 0; EXPECT_EQ(6, tab->FindInPage(L"goa", FWD, IGNORE_CASE, false, &ordinal)); EXPECT_EQ(1, ordinal); - // FindNext returns -1 for match count because it doesn't bother with - // recounting the number of matches. We don't care about the match count - // anyway in this case, we just want to check the ordinal. - EXPECT_EQ(-1, tab->FindInPage(L"goa", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(6, tab->FindInPage(L"goa", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(2, ordinal); - EXPECT_EQ(-1, tab->FindInPage(L"goa", FWD, IGNORE_CASE, true, &ordinal)); + EXPECT_EQ(6, tab->FindInPage(L"goa", FWD, IGNORE_CASE, true, &ordinal)); EXPECT_EQ(3, ordinal); // Add space to search (should result in no matches). EXPECT_EQ(0, tab->FindInPage(L"goa ", FWD, IGNORE_CASE, false, &ordinal)); - EXPECT_EQ(-1, ordinal); + EXPECT_EQ(0, ordinal); // Remove the space, should be back to '3 out of 6') EXPECT_EQ(6, tab->FindInPage(L"goa", FWD, IGNORE_CASE, false, &ordinal)); EXPECT_EQ(3, ordinal); @@ -170,10 +161,7 @@ TEST_F(FindInPageControllerTest, FindCrash_Issue1341577) { // against the frame, otherwise an active frame pointer is set and it wont // produce the crash. EXPECT_EQ(1, tab->FindInPage(L"\u0D4C", FWD, IGNORE_CASE, false, NULL)); - // FindNext returns -1 for match count because it doesn't bother with - // recounting the number of matches. We don't care about the match count - // anyway in this case, we just want to make sure it doesn't crash. - EXPECT_EQ(-1, tab->FindInPage(L"\u0D4C", FWD, IGNORE_CASE, true, NULL)); + EXPECT_EQ(1, tab->FindInPage(L"\u0D4C", FWD, IGNORE_CASE, true, NULL)); // This should work fine. EXPECT_EQ(1, tab->FindInPage(L"\u0D24\u0D46", FWD, IGNORE_CASE, false, NULL)); @@ -223,12 +211,12 @@ TEST_F(FindInPageControllerTest, FindMovesOnTabClose_Issue1343052) { EXPECT_TRUE(WaitForBookmarkBarVisibilityChange(browser.get(), true)); // Open the Find window and wait for it to animate. - EXPECT_TRUE(tabA->OpenFindInPage()); - EXPECT_TRUE(WaitForFindWindowVisibilityChange(tabA.get(), true)); + EXPECT_TRUE(browser->OpenFindInPage()); + EXPECT_TRUE(WaitForFindWindowVisibilityChange(browser.get(), true)); // Find its location. int x = -1, y = -1; - EXPECT_TRUE(tabA->GetFindWindowLocation(&x, &y)); + EXPECT_TRUE(browser->GetFindWindowLocation(&x, &y)); // Open another tab (tab B). EXPECT_TRUE(browser->AppendTab(url)); @@ -239,7 +227,7 @@ TEST_F(FindInPageControllerTest, FindMovesOnTabClose_Issue1343052) { // See if the Find window has moved. int new_x = -1, new_y = -1; - EXPECT_TRUE(tabA->GetFindWindowLocation(&new_x, &new_y)); + EXPECT_TRUE(browser->GetFindWindowLocation(&new_x, &new_y)); EXPECT_EQ(x, new_x); EXPECT_EQ(y, new_y); @@ -249,7 +237,7 @@ TEST_F(FindInPageControllerTest, FindMovesOnTabClose_Issue1343052) { EXPECT_TRUE(WaitForBookmarkBarVisibilityChange(browser.get(), false)); // Bookmark bar has moved, reset our coordinates. - EXPECT_TRUE(tabA->GetFindWindowLocation(&x, &y)); + EXPECT_TRUE(browser->GetFindWindowLocation(&x, &y)); // Open another tab (tab C). EXPECT_TRUE(browser->AppendTab(url)); @@ -259,7 +247,7 @@ TEST_F(FindInPageControllerTest, FindMovesOnTabClose_Issue1343052) { EXPECT_TRUE(tabC->Close(true)); // See if the Find window has moved. - EXPECT_TRUE(tabA->GetFindWindowLocation(&new_x, &new_y)); + EXPECT_TRUE(browser->GetFindWindowLocation(&new_x, &new_y)); EXPECT_EQ(x, new_x); EXPECT_EQ(y, new_y); @@ -272,6 +260,7 @@ TEST_F(FindInPageControllerTest, FindDisappearOnNavigate) { ASSERT_TRUE(NULL != server.get()); GURL url = server->TestServerPageW(kUserSelectPage); + GURL url2 = server->TestServerPageW(kFramePage); scoped_ptr<TabProxy> tab(GetActiveTab()); ASSERT_TRUE(tab->NavigateToURL(url)); WaitUntilTabCount(1); @@ -280,14 +269,14 @@ TEST_F(FindInPageControllerTest, FindDisappearOnNavigate) { ASSERT_TRUE(browser.get() != NULL); // Open the Find window and wait for it to animate. - EXPECT_TRUE(tab->OpenFindInPage()); - EXPECT_TRUE(WaitForFindWindowVisibilityChange(tab.get(), true)); + EXPECT_TRUE(browser->OpenFindInPage()); + EXPECT_TRUE(WaitForFindWindowVisibilityChange(browser.get(), true)); // Reload the tab and make sure Find box doesn't go away. EXPECT_TRUE(tab->Reload()); - EXPECT_TRUE(WaitForFindWindowVisibilityChange(tab.get(), true)); + EXPECT_TRUE(WaitForFindWindowVisibilityChange(browser.get(), true)); // Navigate and make sure the Find box goes away. - EXPECT_TRUE(tab->NavigateToURL(url)); - EXPECT_TRUE(WaitForFindWindowVisibilityChange(tab.get(), false)); + EXPECT_TRUE(tab->NavigateToURL(url2)); + EXPECT_TRUE(WaitForFindWindowVisibilityChange(browser.get(), false)); } diff --git a/chrome/browser/views/find_bar_win_unittest.cc b/chrome/browser/views/find_bar_win_unittest.cc index c80e26d..4ef345c 100644 --- a/chrome/browser/views/find_bar_win_unittest.cc +++ b/chrome/browser/views/find_bar_win_unittest.cc @@ -22,7 +22,7 @@ const std::wstring kTooFewMatchesPage = L"files/find_in_page/bug_1155639.html"; class FindInPageNotificationObserver : public NotificationObserver { public: - FindInPageNotificationObserver(TabContents* parent_tab) + explicit FindInPageNotificationObserver(TabContents* parent_tab) : parent_tab_(parent_tab), active_match_ordinal_(-1), number_of_matches_(0) { @@ -89,10 +89,12 @@ class FindInPageControllerTest : public InProcessBrowserTest { WebContents* web_contents = browser()->GetSelectedTabContents()->AsWebContents(); if (web_contents) { - web_contents->view()->FindInPage(*browser(), true, forward == FWD); + web_contents->set_current_find_request_id( + FindInPageNotificationObserver::kFindInPageRequestId); web_contents->render_view_host()->StartFinding( FindInPageNotificationObserver::kFindInPageRequestId, - search_string, forward == FWD, match_case == CASE_SENSITIVE, find_next); + search_string, forward == FWD, match_case == CASE_SENSITIVE, + find_next); return FindInPageNotificationObserver(web_contents).number_of_matches(); } return 0; diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index c0476d5..be0020f 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -21,6 +21,7 @@ #include "chrome/browser/views/bug_report_view.h" #include "chrome/browser/views/clear_browsing_data.h" #include "chrome/browser/views/download_shelf_view.h" +#include "chrome/browser/views/find_bar_win.h" #include "chrome/browser/views/frame/browser_frame.h" #include "chrome/browser/views/fullscreen_exit_bubble.h" #include "chrome/browser/views/html_dialog_view.h" @@ -86,6 +87,8 @@ static const int kDefaultHungPluginDetectFrequency = 2000; static const int kDefaultPluginMessageResponseTimeout = 30000; // The number of milliseconds between loading animation frames. static const int kLoadingAnimationFrameTimeMs = 30; +// The amount of space we expect the window border to take up. +static const int kWindowBorderWidth = 5; // If not -1, windows are shown with this state. static int explicit_show_state = -1; @@ -180,6 +183,8 @@ BrowserView::BrowserView(Browser* browser) active_bookmark_bar_(NULL), active_download_shelf_(NULL), toolbar_(NULL), + infobar_container_(NULL), + find_bar_y_(0), contents_container_(NULL), initialized_(false), fullscreen_(false), @@ -253,6 +258,44 @@ gfx::Rect BrowserView::GetClientAreaBounds() const { return container_bounds; } +bool BrowserView::ShouldFindBarBlendWithBookmarksBar() const { + if (bookmark_bar_view_.get()) + return bookmark_bar_view_->IsAlwaysShown(); + return false; +} + +gfx::Rect BrowserView::GetFindBarBoundingBox() const { + // This function returns the area the Find Bar can be laid out within. This + // basically implies the "user-perceived content area" of the browser window + // excluding the vertical scrollbar. This is not quite so straightforward as + // positioning based on the TabContentsContainerView since the BookmarkBarView + // may be visible but not persistent (in the New Tab case) and we position + // the Find Bar over the top of it in that case since the BookmarkBarView is + // not _visually_ connected to the Toolbar. + + // First determine the bounding box of the content area in Widget coordinates. + gfx::Rect bounding_box(contents_container_->bounds()); + + gfx::Point topleft; + views::View::ConvertPointToWidget(contents_container_, &topleft); + bounding_box.set_origin(topleft); + + // Adjust the position and size of the bounding box by the find bar offset + // calculated during the last Layout. + int height_delta = find_bar_y_ - bounding_box.y(); + bounding_box.set_y(find_bar_y_); + bounding_box.set_height(std::max(0, bounding_box.height() + height_delta)); + + // Finally decrease the width of the bounding box by the width of the vertical + // scroll bar. + int scrollbar_width = views::NativeScrollBar::GetVerticalScrollBarWidth(); + bounding_box.set_width(std::max(0, bounding_box.width() - scrollbar_width)); + if (UILayoutIsRightToLeft()) + bounding_box.set_x(bounding_box.x() + scrollbar_width); + + return bounding_box; +} + int BrowserView::GetTabStripHeight() const { return tabstrip_->GetPreferredHeight(); } @@ -421,6 +464,8 @@ void BrowserView::Init() { infobar_container_ = new InfoBarContainer(this); AddChildView(infobar_container_); + find_bar_.reset(new FindBarWin(this)); + contents_container_ = new TabContentsContainerView; set_contents_view(contents_container_); AddChildView(contents_container_); @@ -694,6 +739,10 @@ void BrowserView::ToggleBookmarkBar() { BookmarkBarView::ToggleWhenVisible(browser_->profile()); } +void BrowserView::ShowFindBar() { + find_bar_->Show(); +} + void BrowserView::ShowAboutChromeDialog() { views::Window::CreateChromeWindow( GetWidget()->GetHWND(), gfx::Rect(), @@ -800,6 +849,22 @@ LocationBarView* BrowserView::GetLocationBarView() const { return toolbar_->GetLocationBarView(); } +bool BrowserView::GetFindBarWindowInfo(gfx::Point* position, + bool* fully_visible) const { + CRect window_rect; + if (!find_bar_.get() || + !::IsWindow(find_bar_->GetHWND()) || + !::GetWindowRect(find_bar_->GetHWND(), &window_rect)) { + *position = gfx::Point(0, 0); + *fully_visible = false; + return false; + } + + *position = gfx::Point(window_rect.TopLeft().x, window_rect.TopLeft().y); + *fully_visible = find_bar_->IsVisible() && !find_bar_->IsAnimating(); + return true; +} + /////////////////////////////////////////////////////////////////////////////// // BrowserView, NotificationObserver implementation: @@ -828,6 +893,10 @@ void BrowserView::TabDetachedAt(TabContents* contents, int index) { // on the selected TabContents when it is removed. infobar_container_->ChangeTabContents(NULL); contents_container_->SetTabContents(NULL); + // When dragging the last TabContents out of a window there is no selection + // notification that causes the find bar for that window to be un-registered + // for notifications from this TabContents. + find_bar_->ChangeWebContents(NULL); } } @@ -862,6 +931,9 @@ void BrowserView::TabSelectedAt(TabContents* old_contents, toolbar_->SetProfile(new_contents->profile()); UpdateToolbar(new_contents, true); UpdateUIForContents(new_contents); + + if (find_bar_.get() && new_contents->AsWebContents()) + find_bar_->ChangeWebContents(new_contents->AsWebContents()); } void BrowserView::TabStripEmpty() { @@ -1114,6 +1186,11 @@ void BrowserView::Layout() { top = LayoutBookmarkAndInfoBars(top); int bottom = LayoutDownloadShelf(); LayoutTabContents(top, bottom); + // This must be done _after_ we lay out the TabContents since this code calls + // back into us to find the bounding box the find bar must be laid out within, + // and that code depends on the TabContentsContainer's bounds being up to + // date. + find_bar_->MoveWindowIfNecessary(gfx::Rect(), true); LayoutStatusBubble(bottom); #ifdef CHROME_PERSONALIZATION if (IsPersonalizationEnabled()) { @@ -1121,8 +1198,6 @@ void BrowserView::Layout() { toolbar_, 0); } #endif - - SchedulePaint(); } @@ -1267,16 +1342,17 @@ int BrowserView::LayoutToolbar(int top) { } int BrowserView::LayoutBookmarkAndInfoBars(int top) { + find_bar_y_ = top + y() - 1; if (bookmark_bar_view_.get()) { // If we're showing the Bookmark bar in detached style, then we need to show // any Info bar _above_ the Bookmark bar, since the Bookmark bar is styled // to look like it's part of the page. if (bookmark_bar_view_->IsDetachedStyle()) return LayoutBookmarkBar(LayoutInfoBar(top)); - // Otherwise, Bookmark bar first, Info bar second. top = LayoutBookmarkBar(top); } + find_bar_y_ = top + y() - 1; return LayoutInfoBar(top); } diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index c91af8e..c228246 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -24,6 +24,7 @@ class BookmarkBarView; class Browser; class BrowserToolbarView; class EncodingMenuControllerDelegate; +class FindBarWin; class FullscreenExitBubble; class InfoBarContainer; class Menu; @@ -73,6 +74,19 @@ class BrowserView : public BrowserWindow, // BrowserView's parent. gfx::Rect GetClientAreaBounds() const; + // Returns true if the Find Bar should be rendered such that it appears to + // blend with the Bookmarks Bar. False if it should appear to blend with the + // main Toolbar. The return value will vary depending on whether or not the + // Bookmark Bar is always shown. + bool ShouldFindBarBlendWithBookmarksBar() const; + + // Returns the constraining bounding box that should be used to lay out the + // FindBar within. This is _not_ the size of the find bar, just the bounding + // box it should be laid out within. The coordinate system of the returned + // rect is in the coordinate system of the frame, since the FindBar is a child + // window. + gfx::Rect GetFindBarBoundingBox() const; + // Returns the preferred height of the TabStrip. Used to position the OTR // avatar icon. int GetTabStripHeight() const; @@ -181,6 +195,7 @@ class BrowserView : public BrowserWindow, virtual bool IsBookmarkBarVisible() const; virtual gfx::Rect GetRootWindowResizerRect() const; virtual void ToggleBookmarkBar(); + virtual void ShowFindBar(); virtual void ShowAboutChromeDialog(); virtual void ShowBookmarkManager(); virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked); @@ -193,6 +208,8 @@ class BrowserView : public BrowserWindow, virtual void ShowNewProfileDialog(); virtual void ShowHTMLDialog(HtmlDialogContentsDelegate* delegate, void* parent_window); + virtual bool GetFindBarWindowInfo(gfx::Point* position, + bool* fully_visible) const; // Overridden from BrowserWindowTesting: virtual BookmarkBarView* GetBookmarkBarView() const; @@ -372,6 +389,13 @@ class BrowserView : public BrowserWindow, // The InfoBarContainer that contains InfoBars for the current tab. InfoBarContainer* infobar_container_; + // The Find Bar. This may be NULL if there is no Find Bar, and if it is + // non-NULL, it may or may not be visible. + scoped_ptr<FindBarWin> find_bar_; + + // The distance the FindBar is from the top of the window, in pixels. + int find_bar_y_; + // The view that contains the selected TabContents. TabContentsContainerView* contents_container_; @@ -437,7 +461,7 @@ class BrowserView : public BrowserWindow, bool personalization_enabled_; #endif - DISALLOW_EVIL_CONSTRUCTORS(BrowserView); + DISALLOW_COPY_AND_ASSIGN(BrowserView); }; #endif // CHROME_BROWSER_VIEWS_FRAME_BROWSER_VIEW_H_ diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 4a5f360..22286f5 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -146,7 +146,7 @@ class RenderViewExtraRequestData : public WebRequest::ExtraData { private: int32 pending_page_id_; - DISALLOW_EVIL_CONSTRUCTORS(RenderViewExtraRequestData); + DISALLOW_COPY_AND_ASSIGN(RenderViewExtraRequestData); }; } // namespace @@ -2191,28 +2191,27 @@ void RenderView::OnFind(const FindInPageRequest& request) { // fix for 792423. webview()->SetFocusedFrame(NULL); - // We send back word that we found some matches, because we don't want to lag - // when notifying the user that we found something. At this point we only know - // that we found 1 match, but the scoping effort will tell us more. However, - // if this is a FindNext request, the scoping effort is already under way, or - // done already, so we have partial results. In that case we set it to -1 so - // that it gets ignored by the FindInPageController. - int match_count = result ? 1 : 0; // 1 here means possibly more coming. - if (request.find_next) - match_count = -1; + if (request.find_next) { + // Force the main_frame to report the actual count. + main_frame->IncreaseMatchCount(0, request.request_id); + } else { + // If nothing is found, set result to "0 of 0", otherwise, set it to + // "-1 of 1" to indicate that we found at least one item, but we don't know + // yet what is active. + int ordinal = result ? -1 : 0; // -1 here means, we might know more later. + int match_count = result ? 1 : 0; // 1 here means possibly more coming. - // If we find no matches (or if this is Find Next) then this will be our last - // status update. Otherwise the scoping effort will send more results. - bool final_status_update = !result || request.find_next; + // If we find no matches then this will be our last status update. + // Otherwise the scoping effort will send more results. + bool final_status_update = !result; - // Send the search result over to the browser process. - Send(new ViewHostMsg_Find_Reply(routing_id_, request.request_id, - match_count, - selection_rect, - -1, // Don't update active match ordinal. - final_status_update)); + // Send the search result over to the browser process. + Send(new ViewHostMsg_Find_Reply(routing_id_, request.request_id, + match_count, + selection_rect, + ordinal, + final_status_update)); - if (!request.find_next) { // Scoping effort begins, starting with the mainframe. search_frame = main_frame; @@ -2871,7 +2870,7 @@ MessageLoop* RenderView::GetMessageLoopForIO() { void RenderView::OnRequestAudioPacket(int stream_id) { AudioRendererImpl* audio_renderer = audio_renderers_.Lookup(stream_id); - if (!audio_renderer){ + if (!audio_renderer) { NOTREACHED(); return; } @@ -2881,7 +2880,7 @@ void RenderView::OnRequestAudioPacket(int stream_id) { void RenderView::OnAudioStreamCreated( int stream_id, base::SharedMemoryHandle handle, int length) { AudioRendererImpl* audio_renderer = audio_renderers_.Lookup(stream_id); - if (!audio_renderer){ + if (!audio_renderer) { NOTREACHED(); return; } @@ -2891,7 +2890,7 @@ void RenderView::OnAudioStreamCreated( void RenderView::OnAudioStreamStateChanged( int stream_id, AudioOutputStream::State state, int info) { AudioRendererImpl* audio_renderer = audio_renderers_.Lookup(stream_id); - if (!audio_renderer){ + if (!audio_renderer) { NOTREACHED(); return; } @@ -2900,7 +2899,7 @@ void RenderView::OnAudioStreamStateChanged( void RenderView::OnAudioStreamVolume(int stream_id, double left, double right) { AudioRendererImpl* audio_renderer = audio_renderers_.Lookup(stream_id); - if (!audio_renderer){ + if (!audio_renderer) { NOTREACHED(); return; } diff --git a/chrome/test/automation/browser_proxy.cc b/chrome/test/automation/browser_proxy.cc index 87f2746..c13fd29 100644 --- a/chrome/test/automation/browser_proxy.cc +++ b/chrome/test/automation/browser_proxy.cc @@ -251,6 +251,35 @@ bool BrowserProxy::WaitForTabToBecomeActive(int tab, return false; } +bool BrowserProxy::OpenFindInPage() { + if (!is_valid()) + return false; + + return sender_->Send(new AutomationMsg_OpenFindInPage(0, handle_)); + // This message expects no response. +} + +bool BrowserProxy::GetFindWindowLocation(int* x, int* y) { + if (!is_valid() || !x || !y) + return false; + + return sender_->Send( + new AutomationMsg_FindWindowLocation(0, handle_, x, y)); +} + +bool BrowserProxy::IsFindWindowFullyVisible(bool* is_visible) { + if (!is_valid()) + return false; + + if (!is_visible) { + NOTREACHED(); + return false; + } + + return sender_->Send( + new AutomationMsg_FindWindowVisibility(0, handle_, is_visible)); +} + bool BrowserProxy::GetHWND(HWND* handle) const { if (!is_valid()) return false; @@ -319,7 +348,7 @@ bool BrowserProxy::GetBooleanPreference(const std::wstring& name, return false; bool result = false; - + sender_->Send(new AutomationMsg_GetBooleanPreference(0, handle_, name, value, &result)); return result; diff --git a/chrome/test/automation/browser_proxy.h b/chrome/test/automation/browser_proxy.h index 4df9269..9a61993 100644 --- a/chrome/test/automation/browser_proxy.h +++ b/chrome/test/automation/browser_proxy.h @@ -144,6 +144,18 @@ class BrowserProxy : public AutomationResourceProxy { // Returns false if the tab does not become active. bool WaitForTabToBecomeActive(int tab, int wait_timeout); + // Opens the FindInPage box. Note: If you just want to search within a tab + // you don't need to call this function, just use FindInPage(...) directly. + bool OpenFindInPage(); + + // Get the x, y coordinates for the Find window. If animating, |x| and |y| + // will be -1, -1. Returns false on failure. + bool GetFindWindowLocation(int* x, int* y); + + // Returns whether the Find window is fully visible If animating, |is_visible| + // will be false. Returns false on failure. + bool IsFindWindowFullyVisible(bool* is_visible); + // Gets the outermost HWND that corresponds to the given browser. // Returns true if the call was successful. // Note that ideally this should go and the version of WindowProxy should be diff --git a/chrome/test/automation/tab_proxy.cc b/chrome/test/automation/tab_proxy.cc index f0f9a72..e36d683 100644 --- a/chrome/test/automation/tab_proxy.cc +++ b/chrome/test/automation/tab_proxy.cc @@ -43,35 +43,6 @@ bool TabProxy::IsShelfVisible(bool* is_visible) { is_visible)); } -bool TabProxy::OpenFindInPage() { - if (!is_valid()) - return false; - - return sender_->Send(new AutomationMsg_OpenFindInPage(0, handle_)); - // This message expects no response. -} - -bool TabProxy::IsFindWindowFullyVisible(bool* is_visible) { - if (!is_valid()) - return false; - - if (!is_visible) { - NOTREACHED(); - return false; - } - - return sender_->Send(new AutomationMsg_FindWindowVisibility( - 0, handle_, is_visible)); -} - -bool TabProxy::GetFindWindowLocation(int* x, int* y) { - if (!is_valid() || !x || !y) - return false; - - return sender_->Send(new AutomationMsg_FindWindowLocation( - 0, handle_, x, y)); -} - int TabProxy::FindInPage(const std::wstring& search_string, FindInPageDirection forward, FindInPageCase match_case, diff --git a/chrome/test/automation/tab_proxy.h b/chrome/test/automation/tab_proxy.h index f9a8339..1e393f54 100644 --- a/chrome/test/automation/tab_proxy.h +++ b/chrome/test/automation/tab_proxy.h @@ -159,18 +159,6 @@ class TabProxy : public AutomationResourceProxy { // unchanged. bool IsShelfVisible(bool* is_visible); - // Opens the FindInPage box. Note: If you just want to search within a tab - // you don't need to call this function, just use FindInPage(...) directly. - bool OpenFindInPage(); - - // Returns whether the Find window is fully visible If animating, |is_visible| - // will be false. Returns false on failure. - bool IsFindWindowFullyVisible(bool* is_visible); - - // Get the x, y coordinates for the Find window. If animating, |x| and |y| - // will be -1, -1. Returns false on failure. - bool GetFindWindowLocation(int* x, int* y); - // Starts a search within the current tab. The parameter |search_string| // specifies what string to search for, |forward| specifies whether to search // in forward direction, and |match_case| specifies case sensitivity diff --git a/chrome/test/test_browser_window.h b/chrome/test/test_browser_window.h index f474f71..e583400 100644 --- a/chrome/test/test_browser_window.h +++ b/chrome/test/test_browser_window.h @@ -48,6 +48,7 @@ class TestBrowserWindow : public BrowserWindow { virtual bool IsBookmarkBarVisible() const { return false; } virtual gfx::Rect GetRootWindowResizerRect() const { return gfx::Rect(); } virtual void ToggleBookmarkBar() {} + virtual void ShowFindBar() {} virtual void ShowAboutChromeDialog() {} virtual void ShowBookmarkManager() {} virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked) {} @@ -60,7 +61,8 @@ class TestBrowserWindow : public BrowserWindow { virtual void ShowNewProfileDialog() {} virtual void ShowHTMLDialog(HtmlDialogContentsDelegate* delegate, void* parent_window) {} - + virtual bool GetFindBarWindowInfo(gfx::Point* position, + bool* fully_visible) const { return false; } protected: virtual void DestroyBrowser() {} diff --git a/chrome/test/ui/ui_test.cc b/chrome/test/ui/ui_test.cc index fc3b9a0..ff30346 100644 --- a/chrome/test/ui/ui_test.cc +++ b/chrome/test/ui/ui_test.cc @@ -399,7 +399,6 @@ void UITest::QuitBrowser() { browsers.push_back(browser_proxy); } - //for (HandleVector::iterator iter = handles.begin(); iter != handles.end(); for (BrowserVector::iterator iter = browsers.begin(); iter != browsers.end(); ++iter) { // Use ApplyAccelerator since it doesn't wait @@ -518,12 +517,12 @@ bool UITest::WaitForDownloadShelfVisible(TabProxy* tab) { return false; } -bool UITest::WaitForFindWindowVisibilityChange(TabProxy* tab, +bool UITest::WaitForFindWindowVisibilityChange(BrowserProxy* browser, bool wait_for_open) { const int kCycles = 20; for (int i = 0; i < kCycles; i++) { bool visible = false; - if (!tab->IsFindWindowFullyVisible(&visible)) + if (!browser->IsFindWindowFullyVisible(&visible)) return false; // Some error. if (visible == wait_for_open) return true; // Find window visibility change complete. @@ -775,7 +774,7 @@ void UITest::WaitForFinish(const std::string &name, // The webpage being tested has javascript which sets a cookie // which signals completion of the test. The cookie name is // a concatenation of the test name and the test id. This allows - // us to run multiple tests within a single webpage and test + // us to run multiple tests within a single webpage and test // that they all c std::string cookie_name = name; cookie_name.append("."); @@ -785,7 +784,7 @@ void UITest::WaitForFinish(const std::string &name, scoped_ptr<TabProxy> tab(GetActiveTab()); - bool test_result = WaitUntilCookieValue(tab.get(), url, + bool test_result = WaitUntilCookieValue(tab.get(), url, cookie_name.c_str(), kIntervalMilliSeconds, wait_time, expected_cookie_value.c_str()); diff --git a/chrome/test/ui/ui_test.h b/chrome/test/ui/ui_test.h index 31ad827..a0436f9 100644 --- a/chrome/test/ui/ui_test.h +++ b/chrome/test/ui/ui_test.h @@ -145,7 +145,7 @@ class UITest : public testing::Test { // Waits until the Find window has become fully visible (if |wait_for_open| is // true) or fully hidden (if |wait_for_open| is false). This function can time // out (return false) if the window doesn't appear within a specific time. - bool WaitForFindWindowVisibilityChange(TabProxy* tab, + bool WaitForFindWindowVisibilityChange(BrowserProxy* browser, bool wait_for_open); // Waits until the Bookmark bar has stopped animating and become fully visible @@ -334,7 +334,7 @@ class UITest : public testing::Test { DictionaryValue* GetDefaultProfilePreferences(); // Generate the URL for testing a particular test. - // HTML for the tests is all located in + // HTML for the tests is all located in // test_root_directory\test_directory\<testcase> static GURL GetTestUrl(const std::wstring& test_directory, const std::wstring &test_case); diff --git a/chrome/views/view.cc b/chrome/views/view.cc index 0385df4..c61cbbd 100644 --- a/chrome/views/view.cc +++ b/chrome/views/view.cc @@ -57,7 +57,7 @@ class RestoreFocusTask : public Task { // The target view. View* view_; - DISALLOW_EVIL_CONSTRUCTORS(RestoreFocusTask); + DISALLOW_COPY_AND_ASSIGN(RestoreFocusTask); }; ///////////////////////////////////////////////////////////////////////////// @@ -71,7 +71,7 @@ View::View() group_(-1), enabled_(true), focusable_(false), - bounds_(0,0,0,0), + bounds_(0, 0, 0, 0), parent_(NULL), should_restore_focus_(false), is_visible_(true), @@ -117,7 +117,7 @@ gfx::Rect View::GetBounds(PositionMirroringSettings settings) const { // rectangle appropriately. if (settings == APPLY_MIRRORING_TRANSFORMATION) bounds.set_x(MirroredX()); - + return bounds; } @@ -206,6 +206,7 @@ void View::Layout() { if (layout_manager_.get()) { layout_manager_->Layout(this); SchedulePaint(); + return; } // Lay out contents of child Views @@ -441,7 +442,7 @@ void View::ShowContextMenu(int x, int y, bool is_mouse_gesture) { if (!context_menu_controller_) return; - context_menu_controller_->ShowContextMenu(this, x, y, is_mouse_gesture); + context_menu_controller_->ShowContextMenu(this, x, y, is_mouse_gesture); } ///////////////////////////////////////////////////////////////////////////// diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc index fcfd641..81af58d 100644 --- a/webkit/glue/webframe_impl.cc +++ b/webkit/glue/webframe_impl.cc @@ -868,22 +868,21 @@ bool WebFrameImpl::Find(const FindInPageRequest& request, if (active_match_index_ + 1 == 0) active_match_index_ = last_match_count_ - 1; } - } - #if defined(OS_WIN) - // TODO(pinkerton): Fix Mac scrolling to be more like Win ScrollView - if (selection_rect) { - gfx::Rect rect = webkit_glue::FromIntRect( - frame()->view()->convertToContainingWindow(curr_selection_rect)); - rect.Offset(-frameview()->scrollOffset().width(), - -frameview()->scrollOffset().height()); - *selection_rect = rect; - - ReportFindInPageSelection(rect, - active_match_index_ + 1, - request.request_id); - } + // TODO(pinkerton): Fix Mac scrolling to be more like Win ScrollView + if (selection_rect) { + gfx::Rect rect = webkit_glue::FromIntRect( + frame()->view()->convertToContainingWindow(curr_selection_rect)); + rect.Offset(-frameview()->scrollOffset().width(), + -frameview()->scrollOffset().height()); + *selection_rect = rect; + + ReportFindInPageSelection(rect, + active_match_index_ + 1, + request.request_id); + } #endif + } } else { // Nothing was found in this frame. active_match_ = NULL; |