From c5b90374f3e454dbc5d5f2a4f23c49e7cba93147 Mon Sep 17 00:00:00 2001 From: "shess@chromium.org" Date: Thu, 22 Apr 2010 00:03:07 +0000 Subject: Temporarily revert certain Omnibox, toolbar, tab animations, and other UI changes for purposes of testing and merging into mstone-5. Also ++kThemePackVersion and regenerate the cached theme pak. Reverted changes: r45213: GTK: Override cursor colors in chrome-theme mode. r45103: Support drawing nano tabs in the tabstrip. r45084: GTK: Position the EV certificate stuff inside a green bubble. r44979: Subclassing the InfoBubble to handle anchoring bubbles basedon... r44957: GTK: Tint the geolocation icons in gtk mode. r44943: Changes FormatURL to not strip http if the host starts with ft... r44930: Remove an icon that is no longer used. r44929: SSL UI changes, Windows, code side (images are separate). r44859: SSL UI changes (icons). TBRed since trybots hate binary patches. r44822: GTK: Select better greens in the native omnibox popup. r44814: GTK: navigate to URL on PRIMARY when middle-clicking the locat... r44789: [Mac] Bookmark star missing on NTP and BMM. r44775: [Mac] Centralize hack to make tests work with AutocompleteClas... r44678: Display the SECURITY_WARNING status in the location bar for the r44648: [Mac] Add an arrow cursor rect for the location image. r44615: Revert r44611 because it may have broken "unit_tests" on "Vist... r44611: Display the SECURITY_WARNING status in the location bar for the r44577: Revert 44572 - [Mac] Update locationbar icon as user types. r44572: [Mac] Update location-bar icon as user types. r44555: GTK: Use correct button mask on reload button. r44545: [Mac] Omnibox text drag drag URL when select-all. r44523: GTK: Prevent inappropriate drag of location bar location icon. r44519: GTK: make the primary selection include the url's scheme when ... r44492: [Mac] Fix search icon in keyword search to be right-side-up. r44415: GTK: Update top padding on icons in the autocomplete popup. r44401: GTK: Tint omnibox icons in GTK mode differently. r44380: GTK: Move reload in gtk mode and fix omnibox popup location. r44282: Fixes crash in autocomplete when typing some URLs. The problem r44273: [Mac] PDF icons for omnibox nits. r44269: Fix build break due to bad merge resolve r44268: Shift omnibox dropdown in and up on Windows, and square off th... r44178: GTK: fix TTS padding. r44177: Round the top left and right edges of the toolbar. r44171: Images only checkin for try server goodness. r44163: GTK: fix padding of autocomplete popup. r44152: [Mac] PDF icons for omnibox. r44145: GTK: Theme the icons in the location bar and use GTK colors fo... r44140: Strips http from the omnibox r44131: Fixes bugs in new tab strip animations where they weren't doin... r44116: Change the default theme colors. r44117: Add newline to EOF to fix CrOS builder. r44115: Make the bottom edges of the opaque frame rounded. r44091: [Mac] No star icon or page actions in omnibox on popups. r44087: Don't allow drag or click on location icon when editing in omn... r44021: [GTK] Add TTS lens graphic to linux TTS box. r44008: [Mac] Tweak location icon spacing in omnibox. r43977: GTK: don't show the star or page actions in ShouldOnlyShowLoca... r43972: Make the firstrun bubble point at a better spot now that the l... r43971: [Mac] Location icon in omnibox as drag source. r43970: Make the star and page action icons not appear on popup windows. r43954: Fixes bug in TabStrip where dragging tab out then back in rapidly r43864: Tweaks to BoundsAnimator/SlideAnimation and TabStrip: r43787: Allow location icon to be dragged & dropped. This also fixes ... r43759: Changes end cap of tab-to-search images. r43740: Change bookmark bar toggle to ctrl-shift-b. r43723: Show Page Info dialog on mouse up, not mouse down. r43677: Fix Mac build failure. r43676: Replace omnibox icons with new set that are all the same size ... r43596: Fix browser test TestStarButtonAccObj. r43593: Disables TestStarButtonAccObj. r43582: Changes tab strip to use BoundsAnimator for tab strip animatio... r43563: GTK: don't show reload button for popup/app windows. r43562: Star/reload shuffle, Windows version. r43540: [Mac] Magnifying glass in keyword-search bubble. r43482: Adds images needed for new tab animation. I'm separating this ... r43422: Add reload mask resource. r43392: GTK: make the location icon a drag source. r43376: [Mac] Move star button into page-actions area of omnibox. r43357: [Mac] Line up omnibox popup under field. r43290: gtk: fix display of icons in omnibox popup r43269: GTK: fix reload button. r43249: [Mac] Rearrange SSL status icon/label in omnibox. r43248: BrowserThemePack: Adds persistant ids for the reload endcaps. r43241: GTK: more location bar updates. r43191: Fix memory leak in BrowserThemePack. r43154: GTK: set the new star button's ID r43151: Fix bad conflict resolution for r43146. r43146: GTK: toolbar reload/star shuffle. r43025: Show the location bar icon (almost) all the time, and have its... r43023: Add new images for new reload button. No code change. r42782: Remove this icon, now that it's no longer used (due to my secu... r42502: Omnibox M5 work, part 1: Security changes r42245: Check in new icons for omnibox security changes alone, so that... BUG=none TEST=Eyjafjallajokull R=pkasting@chromium.org,beng@chromium.org git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45267 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/autocomplete/autocomplete.cc | 72 +- chrome/browser/autocomplete/autocomplete.h | 39 +- .../autocomplete/autocomplete_classifier.cc | 34 - .../browser/autocomplete/autocomplete_classifier.h | 43 - chrome/browser/autocomplete/autocomplete_edit.cc | 134 +- chrome/browser/autocomplete/autocomplete_edit.h | 55 +- .../browser/autocomplete/autocomplete_edit_view.h | 7 - .../autocomplete/autocomplete_edit_view_gtk.cc | 199 +-- .../autocomplete/autocomplete_edit_view_gtk.h | 47 +- .../autocomplete/autocomplete_edit_view_mac.h | 12 +- .../autocomplete/autocomplete_edit_view_mac.mm | 101 +- .../autocomplete/autocomplete_edit_view_win.cc | 82 +- .../autocomplete/autocomplete_edit_view_win.h | 7 +- .../autocomplete/autocomplete_popup_model.cc | 56 +- .../autocomplete/autocomplete_popup_model.h | 20 +- .../browser/autocomplete/autocomplete_popup_view.h | 19 + .../autocomplete/autocomplete_popup_view_gtk.cc | 306 ++--- .../autocomplete/autocomplete_popup_view_gtk.h | 35 +- .../autocomplete/autocomplete_popup_view_mac.h | 4 +- .../autocomplete/autocomplete_popup_view_mac.mm | 89 +- .../autocomplete/history_contents_provider.cc | 6 +- .../browser/autocomplete/history_url_provider.cc | 35 +- chrome/browser/autocomplete/search_provider.cc | 11 +- chrome/browser/bookmarks/bookmark_table_model.cc | 6 +- chrome/browser/bookmarks/bookmark_utils.cc | 3 +- chrome/browser/browser_theme_pack.cc | 79 +- chrome/browser/browser_theme_provider.cc | 40 +- chrome/browser/bubble_positioner.h | 24 + chrome/browser/cert_store.cc | 5 +- chrome/browser/cert_store.h | 8 +- .../browser/chromeos/compact_location_bar_host.cc | 5 + .../browser/chromeos/compact_location_bar_host.h | 4 + .../browser/chromeos/compact_location_bar_view.cc | 88 +- .../browser/chromeos/compact_location_bar_view.h | 24 +- chrome/browser/chromeos/frame/browser_view.cc | 16 +- chrome/browser/chromeos/frame/browser_view.h | 2 + chrome/browser/cocoa/autocomplete_text_field.h | 7 - chrome/browser/cocoa/autocomplete_text_field.mm | 31 +- .../browser/cocoa/autocomplete_text_field_cell.h | 85 +- .../browser/cocoa/autocomplete_text_field_cell.mm | 563 +++----- .../cocoa/autocomplete_text_field_cell_unittest.mm | 139 +- .../cocoa/autocomplete_text_field_editor.mm | 29 - .../cocoa/autocomplete_text_field_unittest.mm | 96 +- chrome/browser/cocoa/bookmark_bubble_controller.mm | 2 +- chrome/browser/cocoa/browser_test_helper.h | 9 - chrome/browser/cocoa/browser_window_controller.mm | 2 +- .../cocoa/browser_window_controller_unittest.mm | 4 +- chrome/browser/cocoa/location_bar_view_mac.h | 108 +- chrome/browser/cocoa/location_bar_view_mac.mm | 243 ++-- .../cocoa/location_bar_view_mac_unittest.mm | 37 +- chrome/browser/cocoa/status_bubble_mac_unittest.mm | 8 +- .../browser/cocoa/tab_strip_controller_unittest.mm | 2 +- chrome/browser/cocoa/toolbar_controller.h | 14 +- chrome/browser/cocoa/toolbar_controller.mm | 104 +- .../browser/cocoa/toolbar_controller_unittest.mm | 34 +- chrome/browser/gtk/accelerators_gtk.cc | 3 +- chrome/browser/gtk/bookmark_bubble_gtk.cc | 2 +- chrome/browser/gtk/browser_toolbar_gtk.cc | 142 +- chrome/browser/gtk/browser_toolbar_gtk.h | 20 +- chrome/browser/gtk/browser_window_gtk.cc | 6 +- chrome/browser/gtk/find_bar_gtk.cc | 2 - chrome/browser/gtk/gtk_theme_provider.cc | 78 +- chrome/browser/gtk/gtk_theme_provider.h | 7 - chrome/browser/gtk/gtk_util.cc | 30 - chrome/browser/gtk/gtk_util.h | 7 - chrome/browser/gtk/location_bar_view_gtk.cc | 448 +++---- chrome/browser/gtk/location_bar_view_gtk.h | 131 +- .../gtk/options/passwords_exceptions_page_gtk.cc | 2 +- chrome/browser/gtk/options/passwords_page_gtk.cc | 4 +- .../browser/gtk/options/url_picker_dialog_gtk.cc | 3 +- chrome/browser/gtk/rounded_window.cc | 4 - chrome/browser/gtk/rounded_window.h | 3 - chrome/browser/gtk/tabs/tab_strip_gtk.cc | 24 +- chrome/browser/gtk/toolbar_star_toggle_gtk.cc | 142 ++ chrome/browser/gtk/toolbar_star_toggle_gtk.h | 76 ++ chrome/browser/location_bar.h | 1 - chrome/browser/net/browser_url_util.cc | 6 +- chrome/browser/net/url_fixer_upper.cc | 8 +- chrome/browser/profile.cc | 17 +- chrome/browser/profile.h | 15 +- .../browser/search_versus_navigate_classifier.cc | 56 + chrome/browser/search_versus_navigate_classifier.h | 52 + chrome/browser/ssl/ssl_browser_tests.cc | 5 +- chrome/browser/ssl/ssl_manager.cc | 27 +- chrome/browser/ssl/ssl_manager.h | 10 +- chrome/browser/ssl/ssl_policy.cc | 15 +- .../tab_contents/render_view_context_menu.cc | 26 +- chrome/browser/theme_resources_util_unittest.cc | 4 +- chrome/browser/toolbar_model.cc | 188 ++- chrome/browser/toolbar_model.h | 58 +- chrome/browser/views/accelerator_table_gtk.cc | 3 +- chrome/browser/views/app_launcher.cc | 76 +- chrome/browser/views/app_launcher.h | 16 +- .../autocomplete_popup_contents_view.cc | 149 ++- .../autocomplete_popup_contents_view.h | 6 +- chrome/browser/views/bookmark_editor_view.cc | 5 +- .../browser_views_accessibility_browsertest.cc | 5 +- chrome/browser/views/bubble_border.cc | 107 +- chrome/browser/views/bubble_border.h | 33 +- chrome/browser/views/constrained_window_win.cc | 20 +- chrome/browser/views/frame/browser_frame_win.cc | 6 +- chrome/browser/views/frame/browser_root_view.cc | 15 +- chrome/browser/views/frame/browser_view.cc | 32 +- .../views/frame/glass_browser_frame_view.cc | 47 +- .../views/frame/opaque_browser_frame_view.cc | 88 +- chrome/browser/views/info_bubble.cc | 74 +- chrome/browser/views/info_bubble.h | 77 +- chrome/browser/views/location_bar_view.cc | 1254 +++++++++--------- chrome/browser/views/location_bar_view.h | 327 ++--- .../browser/views/pinned_contents_info_bubble.cc | 74 -- chrome/browser/views/pinned_contents_info_bubble.h | 89 -- .../browser/views/tabs/dragged_tab_controller.cc | 9 +- chrome/browser/views/tabs/tab_renderer.cc | 204 +-- chrome/browser/views/tabs/tab_renderer.h | 52 +- chrome/browser/views/tabs/tab_strip.cc | 1369 ++++++++++++-------- chrome/browser/views/tabs/tab_strip.h | 248 ++-- chrome/browser/views/toolbar_star_toggle.cc | 133 ++ chrome/browser/views/toolbar_star_toggle.h | 85 ++ chrome/browser/views/toolbar_view.cc | 182 ++- chrome/browser/views/toolbar_view.h | 24 +- chrome/browser/views/url_picker.cc | 6 +- 121 files changed, 4921 insertions(+), 4750 deletions(-) delete mode 100644 chrome/browser/autocomplete/autocomplete_classifier.cc delete mode 100644 chrome/browser/autocomplete/autocomplete_classifier.h create mode 100644 chrome/browser/bubble_positioner.h create mode 100644 chrome/browser/gtk/toolbar_star_toggle_gtk.cc create mode 100644 chrome/browser/gtk/toolbar_star_toggle_gtk.h create mode 100644 chrome/browser/search_versus_navigate_classifier.cc create mode 100644 chrome/browser/search_versus_navigate_classifier.h delete mode 100644 chrome/browser/views/pinned_contents_info_bubble.cc delete mode 100644 chrome/browser/views/pinned_contents_info_bubble.h create mode 100644 chrome/browser/views/toolbar_star_toggle.cc create mode 100644 chrome/browser/views/toolbar_star_toggle.h (limited to 'chrome/browser') diff --git a/chrome/browser/autocomplete/autocomplete.cc b/chrome/browser/autocomplete/autocomplete.cc index ba37681..9c7e942 100644 --- a/chrome/browser/autocomplete/autocomplete.cc +++ b/chrome/browser/autocomplete/autocomplete.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -27,7 +27,6 @@ #include "googleurl/src/url_canon_ip.h" #include "googleurl/src/url_util.h" #include "grit/generated_resources.h" -#include "grit/theme_resources.h" #include "net/base/net_util.h" #include "net/base/registry_controlled_domain.h" #include "net/url_request/url_request.h" @@ -368,18 +367,6 @@ void AutocompleteInput::Clear() { // AutocompleteMatch ---------------------------------------------------------- -AutocompleteMatch::AutocompleteMatch() - : provider(NULL), - relevance(0), - deletable(false), - inline_autocomplete_offset(std::wstring::npos), - transition(PageTransition::GENERATED), - is_history_what_you_typed_match(false), - type(SEARCH_WHAT_YOU_TYPED), - template_url(NULL), - starred(false) { -} - AutocompleteMatch::AutocompleteMatch(AutocompleteProvider* provider, int relevance, bool deletable, @@ -397,40 +384,23 @@ AutocompleteMatch::AutocompleteMatch(AutocompleteProvider* provider, // static std::string AutocompleteMatch::TypeToString(Type type) { - const char* strings[NUM_TYPES] = { - "url-what-you-typed", - "history-url", - "history-title", - "history-body", - "history-keyword", - "navsuggest", - "search-what-you-typed", - "search-history", - "search-suggest", - "search-other-engine", - "open-history-page", - }; - DCHECK(arraysize(strings) == NUM_TYPES); - return strings[type]; -} + switch (type) { + case URL_WHAT_YOU_TYPED: return "url-what-you-typed"; + case HISTORY_URL: return "history-url"; + case HISTORY_TITLE: return "history-title"; + case HISTORY_BODY: return "history-body"; + case HISTORY_KEYWORD: return "history-keyword"; + case NAVSUGGEST: return "navsuggest"; + case SEARCH_WHAT_YOU_TYPED: return "search-what-you-typed"; + case SEARCH_HISTORY: return "search-history"; + case SEARCH_SUGGEST: return "search-suggest"; + case SEARCH_OTHER_ENGINE: return "search-other-engine"; + case OPEN_HISTORY_PAGE: return "open-history-page"; -// static -int AutocompleteMatch::TypeToIcon(Type type) { - int icons[NUM_TYPES] = { - IDR_OMNIBOX_HTTP, - IDR_OMNIBOX_HTTP, - IDR_OMNIBOX_HISTORY, - IDR_OMNIBOX_HISTORY, - IDR_OMNIBOX_HISTORY, - IDR_OMNIBOX_HTTP, - IDR_OMNIBOX_SEARCH, - IDR_OMNIBOX_SEARCH, - IDR_OMNIBOX_SEARCH, - IDR_OMNIBOX_SEARCH, - IDR_OMNIBOX_MORE, - }; - DCHECK(arraysize(icons) == NUM_TYPES); - return icons[type]; + default: + NOTREACHED(); + return std::string(); + } } // static @@ -595,14 +565,10 @@ void AutocompleteProvider::UpdateStarredStateOfMatches() { std::wstring AutocompleteProvider::StringForURLDisplay( const GURL& url, - bool check_accept_lang, - bool trim_http) const { + bool check_accept_lang) const { std::wstring languages = (check_accept_lang && profile_) ? profile_->GetPrefs()->GetString(prefs::kAcceptLanguages) : std::wstring(); - const net::FormatUrlTypes format_types = trim_http ? - net::kFormatUrlOmitAll : net::kFormatUrlOmitUsernamePassword; - return net::FormatUrl(url, languages, format_types, UnescapeRule::SPACES, - NULL, NULL, NULL); + return net::FormatUrl(url, languages); } // AutocompleteResult --------------------------------------------------------- diff --git a/chrome/browser/autocomplete/autocomplete.h b/chrome/browser/autocomplete/autocomplete.h index 54bd9ff..d64fd6c 100644 --- a/chrome/browser/autocomplete/autocomplete.h +++ b/chrome/browser/autocomplete/autocomplete.h @@ -314,24 +314,22 @@ struct AutocompleteMatch { // The type of this match. enum Type { - URL_WHAT_YOU_TYPED = 0, // The input as a URL. - HISTORY_URL, // A past page whose URL contains the input. - HISTORY_TITLE, // A past page whose title contains the input. - HISTORY_BODY, // A past page whose body contains the input. - HISTORY_KEYWORD, // A past page whose keyword contains the input. - NAVSUGGEST, // A suggested URL. - SEARCH_WHAT_YOU_TYPED, // The input as a search query (with the default - // engine). - SEARCH_HISTORY, // A past search (with the default engine) - // containing the input. - SEARCH_SUGGEST, // A suggested search (with the default engine). - SEARCH_OTHER_ENGINE, // A search with a non-default engine. - OPEN_HISTORY_PAGE, // A synthetic result that opens the history page - // to search for the input. - NUM_TYPES, + URL_WHAT_YOU_TYPED, // The input as a URL. + HISTORY_URL, // A past page whose URL contains the input. + HISTORY_TITLE, // A past page whose title contains the input. + HISTORY_BODY, // A past page whose body contains the input. + HISTORY_KEYWORD, // A past page whose keyword contains the input. + NAVSUGGEST, // A suggested URL. + SEARCH_WHAT_YOU_TYPED, // The input as a search query (with the default + // engine). + SEARCH_HISTORY, // A past search (with the default engine) + // containing the input. + SEARCH_SUGGEST, // A suggested search (with the default engine). + SEARCH_OTHER_ENGINE, // A search with a non-default engine. + OPEN_HISTORY_PAGE, // A synthetic result that opens the history page to + // search for the input. }; - AutocompleteMatch(); AutocompleteMatch(AutocompleteProvider* provider, int relevance, bool deletable, @@ -340,10 +338,6 @@ struct AutocompleteMatch { // Converts |type| to a string representation. Used in logging. static std::string TypeToString(Type type); - // Converts |type| to a resource identifier for the appropriate icon for this - // type. - static int TypeToIcon(Type type); - // Comparison function for determining when one match is better than another. static bool MoreRelevant(const AutocompleteMatch& elem1, const AutocompleteMatch& elem2); @@ -561,8 +555,7 @@ class AutocompleteProvider // "Accept Languages" when check_accept_lang is true. Otherwise, it's called // with an empty list. std::wstring StringForURLDisplay(const GURL& url, - bool check_accept_lang, - bool trim_http) const; + bool check_accept_lang) const; // The profile associated with the AutocompleteProvider. Reference is not // owned by us. @@ -783,7 +776,7 @@ class AutocompleteController : public ACProviderListener { const AutocompleteInput& input() const { return input_; } const AutocompleteResult& result() const { return result_; } // This next is temporary and should go away when - // AutocompletePopup::InfoForCurrentSelection() moves to the controller. + // AutocompletePopup::URLsForCurrentSelection() moves to the controller. const AutocompleteResult& latest_result() const { return latest_result_; } bool done() const { return done_ && !update_delay_timer_.IsRunning(); } diff --git a/chrome/browser/autocomplete/autocomplete_classifier.cc b/chrome/browser/autocomplete/autocomplete_classifier.cc deleted file mode 100644 index 3e96ff5..0000000 --- a/chrome/browser/autocomplete/autocomplete_classifier.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/autocomplete/autocomplete_classifier.h" - -#include "chrome/browser/autocomplete/autocomplete.h" -#include "googleurl/src/gurl.h" - -AutocompleteClassifier::AutocompleteClassifier(Profile* profile) - : controller_(new AutocompleteController(profile)) { -} - -AutocompleteClassifier::~AutocompleteClassifier() { -} - -void AutocompleteClassifier::Classify(const std::wstring& text, - const std::wstring& desired_tld, - AutocompleteMatch* match, - GURL* alternate_nav_url) { - controller_->Start(text, desired_tld, true, false, true); - DCHECK(controller_->done()); - const AutocompleteResult& result = controller_->result(); - if (result.empty()) { - if (alternate_nav_url) - *alternate_nav_url = GURL(); - return; - } - - DCHECK(result.default_match() != result.end()); - *match = *result.default_match(); - if (alternate_nav_url) - *alternate_nav_url = result.alternate_nav_url(); -} diff --git a/chrome/browser/autocomplete/autocomplete_classifier.h b/chrome/browser/autocomplete/autocomplete_classifier.h deleted file mode 100644 index 3588c27..0000000 --- a/chrome/browser/autocomplete/autocomplete_classifier.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_CLASSIFIER_H_ -#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_CLASSIFIER_H_ - -#include - -#include "base/basictypes.h" -#include "base/scoped_ptr.h" - -class AutocompleteController; -struct AutocompleteMatch; -class GURL; -class Profile; - -class AutocompleteClassifier { - public: - explicit AutocompleteClassifier(Profile* profile); - virtual ~AutocompleteClassifier(); - - // Given some string |text| that the user wants to use for navigation, - // determines how it should be interpreted. |desired_tld| is the user's - // desired TLD, if any; see AutocompleteInput::desired_tld(). |match| should - // be a non-NULL outparam that will be set to the default match for this - // input, if any (for invalid input, there will be no default match, and - // |match| will be left unchanged). |alternate_nav_url| is a possibly-NULL - // outparam that, if non-NULL, will be set to the navigational URL (if any) in - // case of an accidental search; see comments on - // AutocompleteResult::alternate_nav_url_ in autocomplete.h. - void Classify(const std::wstring& text, - const std::wstring& desired_tld, - AutocompleteMatch* match, - GURL* alternate_nav_url); - - private: - scoped_ptr controller_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(AutocompleteClassifier); -}; - -#endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_CLASSIFIER_H_ diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc index 9b0aefb..f4c2583 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.cc +++ b/chrome/browser/autocomplete/autocomplete_edit.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,7 +9,6 @@ #include "base/basictypes.h" #include "base/utf_string_conversions.h" #include "chrome/app/chrome_dll_resource.h" -#include "chrome/browser/autocomplete/autocomplete_classifier.h" #include "chrome/browser/autocomplete/autocomplete_edit_view.h" #include "chrome/browser/autocomplete/autocomplete_popup_model.h" #include "chrome/browser/autocomplete/keyword_provider.h" @@ -20,6 +19,7 @@ #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/search_versus_navigate_classifier.h" #include "chrome/common/notification_service.h" #include "googleurl/src/gurl.h" #include "googleurl/src/url_util.h" @@ -44,6 +44,7 @@ AutocompleteEditModel::AutocompleteEditModel( control_key_state_(UP), is_keyword_hint_(false), keyword_ui_state_(NORMAL), + show_search_hint_(true), paste_and_go_transition_(PageTransition::TYPED), profile_(profile) { } @@ -80,7 +81,7 @@ const AutocompleteEditModel::State } return State(user_input_in_progress_, user_text_, keyword_, is_keyword_hint_, - keyword_ui_state_); + keyword_ui_state_, show_search_hint_); } void AutocompleteEditModel::RestoreState(const State& state) { @@ -91,6 +92,7 @@ void AutocompleteEditModel::RestoreState(const State& state) { keyword_ = state.keyword; is_keyword_hint_ = state.is_keyword_hint; keyword_ui_state_ = state.keyword_ui_state; + show_search_hint_ = state.show_search_hint; view_->SetUserText(state.user_text, DisplayTextFromUserText(state.user_text), false); } @@ -120,9 +122,7 @@ void AutocompleteEditModel::SetUserText(const std::wstring& text) { void AutocompleteEditModel::GetDataForURLExport(GURL* url, std::wstring* title, SkBitmap* favicon) { - AutocompleteMatch match; - GetInfoForCurrentText(&match, NULL); - *url = match.destination_url; + *url = GetURLForCurrentText(NULL, NULL, NULL); if (UTF8ToWide(url->possibly_invalid_spec()) == permanent_text_) { *title = controller_->GetTitle(); *favicon = controller_->GetFavIcon(); @@ -134,7 +134,7 @@ std::wstring AutocompleteEditModel::GetDesiredTLD() const { std::wstring(L"com") : std::wstring(); } -bool AutocompleteEditModel::CurrentTextIsURL() const { +bool AutocompleteEditModel::CurrentTextIsURL() { // If !user_input_in_progress_, the permanent text is showing, which should // always be a URL, so no further checking is needed. By avoiding checking in // this case, we avoid calling into the autocomplete providers, and thus @@ -142,15 +142,9 @@ bool AutocompleteEditModel::CurrentTextIsURL() const { if (!user_input_in_progress_) return true; - AutocompleteMatch match; - GetInfoForCurrentText(&match, NULL); - return match.transition == PageTransition::TYPED; -} - -AutocompleteMatch::Type AutocompleteEditModel::CurrentTextType() const { - AutocompleteMatch match; - GetInfoForCurrentText(&match, NULL); - return match.type; + PageTransition::Type transition = PageTransition::LINK; + GetURLForCurrentText(&transition, NULL, NULL); + return transition == PageTransition::TYPED; } bool AutocompleteEditModel::GetURLForText(const std::wstring& text, @@ -180,6 +174,7 @@ void AutocompleteEditModel::Revert() { keyword_.clear(); is_keyword_hint_ = false; keyword_ui_state_ = NORMAL; + show_search_hint_ = permanent_text_.empty(); has_temporary_text_ = false; view_->SetWindowTextAndCaretPos(permanent_text_, has_focus_ ? permanent_text_.length() : 0); @@ -196,11 +191,14 @@ bool AutocompleteEditModel::CanPasteAndGo(const std::wstring& text) const { if (!view_->GetCommandUpdater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL)) return false; - AutocompleteMatch match; - profile_->GetAutocompleteClassifier()->Classify(text, std::wstring(), - &match, &paste_and_go_alternate_nav_url_); - paste_and_go_url_ = match.destination_url; - paste_and_go_transition_ = match.transition; + paste_and_go_url_ = GURL(); + paste_and_go_transition_ = PageTransition::TYPED; + paste_and_go_alternate_nav_url_ = GURL(); + + profile_->GetSearchVersusNavigateClassifier()->Classify(text, std::wstring(), + NULL, &paste_and_go_url_, &paste_and_go_transition_, NULL, + &paste_and_go_alternate_nav_url_); + return paste_and_go_url_.is_valid(); } @@ -217,30 +215,33 @@ void AutocompleteEditModel::PasteAndGo() { void AutocompleteEditModel::AcceptInput(WindowOpenDisposition disposition, bool for_drop) { // Get the URL and transition type for the selected entry. - AutocompleteMatch match; + PageTransition::Type transition; + bool is_history_what_you_typed_match; GURL alternate_nav_url; - GetInfoForCurrentText(&match, &alternate_nav_url); - if (!match.destination_url.is_valid()) + const GURL url(GetURLForCurrentText(&transition, + &is_history_what_you_typed_match, + &alternate_nav_url)); + if (!url.is_valid()) return; - if (UTF8ToWide(match.destination_url.spec()) == permanent_text_) { + if (UTF8ToWide(url.spec()) == permanent_text_) { // When the user hit enter on the existing permanent URL, treat it like a // reload for scoring purposes. We could detect this by just checking // user_input_in_progress_, but it seems better to treat "edits" that end // up leaving the URL unchanged (e.g. deleting the last character and then // retyping it) as reloads too. - match.transition = PageTransition::RELOAD; + transition = PageTransition::RELOAD; } else if (for_drop || ((paste_state_ != NONE) && - match.is_history_what_you_typed_match)) { + is_history_what_you_typed_match)) { // When the user pasted in a URL and hit enter, score it like a link click // rather than a normal typed URL, so it doesn't get inline autocompleted // as aggressively later. - match.transition = PageTransition::LINK; + transition = PageTransition::LINK; } - view_->OpenURL(match.destination_url, disposition, match.transition, - alternate_nav_url, AutocompletePopupModel::kNoMatch, - is_keyword_hint_ ? std::wstring() : keyword_); + view_->OpenURL(url, disposition, transition, alternate_nav_url, + AutocompletePopupModel::kNoMatch, + is_keyword_hint_ ? std::wstring() : keyword_); } void AutocompleteEditModel::SendOpenNotification(size_t selected_line, @@ -324,20 +325,17 @@ void AutocompleteEditModel::OnKillFocus() { } bool AutocompleteEditModel::OnEscapeKeyPressed() { - if (has_temporary_text_) { - AutocompleteMatch match; - popup_->InfoForCurrentSelection(&match, NULL); - if (match.destination_url != original_url_) { - // The user typed something, then selected a different item. Restore the - // text they typed and change back to the default item. - // NOTE: This purposefully does not reset paste_state_. - just_deleted_text_ = false; - has_temporary_text_ = false; - keyword_ui_state_ = original_keyword_ui_state_; - popup_->ResetToDefaultMatch(); - view_->OnRevertTemporaryText(); - return true; - } + if (has_temporary_text_ && + (popup_->URLsForCurrentSelection(NULL, NULL, NULL) != original_url_)) { + // The user typed something, then selected a different item. Restore the + // text they typed and change back to the default item. + // NOTE: This purposefully does not reset paste_state_. + just_deleted_text_ = false; + has_temporary_text_ = false; + keyword_ui_state_ = original_keyword_ui_state_; + popup_->ResetToDefaultMatch(); + view_->OnRevertTemporaryText(); + return true; } // If the user wasn't editing, but merely had focus in the edit, allow @@ -407,24 +405,35 @@ void AutocompleteEditModel::OnUpOrDownKeyPressed(int count) { void AutocompleteEditModel::OnPopupDataChanged( const std::wstring& text, - GURL* destination_for_temporary_text_change, + bool is_temporary_text, const std::wstring& keyword, - bool is_keyword_hint) { + bool is_keyword_hint, + AutocompleteMatch::Type type) { + // We don't want to show the search hint if we're showing a keyword hint or + // selected keyword, or (subtle!) if we would be showing a selected keyword + // but for keyword_ui_state_ == NO_KEYWORD. + const bool show_search_hint = keyword.empty() && + ((type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED) || + (type == AutocompleteMatch::SEARCH_HISTORY) || + (type == AutocompleteMatch::SEARCH_SUGGEST)); + // Update keyword/hint-related local state. bool keyword_state_changed = (keyword_ != keyword) || - ((is_keyword_hint_ != is_keyword_hint) && !keyword.empty()); + ((is_keyword_hint_ != is_keyword_hint) && !keyword.empty()) || + (show_search_hint_ != show_search_hint); if (keyword_state_changed) { keyword_ = keyword; is_keyword_hint_ = is_keyword_hint; + show_search_hint_ = show_search_hint; } // Handle changes to temporary text. - if (destination_for_temporary_text_change != NULL) { + if (is_temporary_text) { const bool save_original_selection = !has_temporary_text_; if (save_original_selection) { // Save the original selection and URL so it can be reverted later. has_temporary_text_ = true; - original_url_ = *destination_for_temporary_text_change; + original_url_ = popup_->URLsForCurrentSelection(NULL, NULL, NULL); original_keyword_ui_state_ = keyword_ui_state_; } if (control_key_state_ == DOWN_WITHOUT_CHANGE) { @@ -533,6 +542,7 @@ void AutocompleteEditModel::Observe(NotificationType type, std::wstring inline_autocomplete_text; std::wstring keyword; bool is_keyword_hint = false; + AutocompleteMatch::Type match_type = AutocompleteMatch::SEARCH_WHAT_YOU_TYPED; const AutocompleteResult* result = Details(details).ptr(); const AutocompleteResult::const_iterator match(result->default_match()); @@ -549,9 +559,11 @@ void AutocompleteEditModel::Observe(NotificationType type, // the OS DNS cache could suffer eviction problems for minimal gain. is_keyword_hint = popup_->GetKeywordForMatch(*match, &keyword); + match_type = match->type; } - OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, is_keyword_hint); + OnPopupDataChanged(inline_autocomplete_text, false, keyword, is_keyword_hint, + match_type); } void AutocompleteEditModel::InternalSetUserText(const std::wstring& text) { @@ -574,14 +586,20 @@ std::wstring AutocompleteEditModel::UserTextFromDisplayText( text : (keyword_ + L" " + text); } -void AutocompleteEditModel::GetInfoForCurrentText( - AutocompleteMatch* match, +GURL AutocompleteEditModel::GetURLForCurrentText( + PageTransition::Type* transition, + bool* is_history_what_you_typed_match, GURL* alternate_nav_url) const { if (popup_->IsOpen() || query_in_progress()) { - popup_->InfoForCurrentSelection(match, alternate_nav_url); - } else { - profile_->GetAutocompleteClassifier()->Classify( - UserTextFromDisplayText(view_->GetText()), GetDesiredTLD(), match, - alternate_nav_url); + return popup_->URLsForCurrentSelection(transition, + is_history_what_you_typed_match, + alternate_nav_url); } + + GURL destination_url; + profile_->GetSearchVersusNavigateClassifier()->Classify( + UserTextFromDisplayText(view_->GetText()), GetDesiredTLD(), NULL, + &destination_url, transition, is_history_what_you_typed_match, + alternate_nav_url); + return destination_url; } diff --git a/chrome/browser/autocomplete/autocomplete_edit.h b/chrome/browser/autocomplete/autocomplete_edit.h index 9f4e973..1a0386c 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.h +++ b/chrome/browser/autocomplete/autocomplete_edit.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -83,12 +83,14 @@ class AutocompleteEditModel : public NotificationObserver { const std::wstring& user_text, const std::wstring& keyword, bool is_keyword_hint, - KeywordUIState keyword_ui_state) + KeywordUIState keyword_ui_state, + bool show_search_hint) : user_input_in_progress(user_input_in_progress), user_text(user_text), keyword(keyword), is_keyword_hint(is_keyword_hint), - keyword_ui_state(keyword_ui_state) { + keyword_ui_state(keyword_ui_state), + show_search_hint(show_search_hint) { } bool user_input_in_progress; @@ -96,6 +98,7 @@ class AutocompleteEditModel : public NotificationObserver { const std::wstring keyword; const bool is_keyword_hint; const KeywordUIState keyword_ui_state; + const bool show_search_hint; }; AutocompleteEditModel(AutocompleteEditView* view, @@ -134,10 +137,7 @@ class AutocompleteEditModel : public NotificationObserver { // Returns true if the current edit contents will be treated as a // URL/navigation, as opposed to a search. - bool CurrentTextIsURL() const; - - // Returns the match type for the current edit contents. - AutocompleteMatch::Type CurrentTextType() const; + bool CurrentTextIsURL(); // Returns true if |text| (which is display text in the current context) // parses as a URL, and in that case sets |url| to the calculated URL. @@ -208,7 +208,7 @@ class AutocompleteEditModel : public NotificationObserver { // Accessors for keyword-related state (see comments on keyword_ and // is_keyword_hint_). std::wstring keyword() const { - return (is_keyword_hint_ || (keyword_ui_state_ != NO_KEYWORD)) ? + return (is_keyword_hint_ ? has_focus_ : (keyword_ui_state_ != NO_KEYWORD)) ? keyword_ : std::wstring(); } bool is_keyword_hint() const { return is_keyword_hint_; } @@ -220,6 +220,10 @@ class AutocompleteEditModel : public NotificationObserver { // currently visible in the edit. void ClearKeyword(const std::wstring& visible_text); + // True if we should show the "Type to search" hint (see comments on + // show_search_hint_). + bool show_search_hint() const { return has_focus_ && show_search_hint_; } + // Returns true if a query to an autocomplete provider is currently // in progress. This logic should in the future live in // AutocompleteController but resides here for now. This method is used by @@ -256,20 +260,21 @@ class AutocompleteEditModel : public NotificationObserver { // Called when any relevant data changes. This rolls together several // separate pieces of data into one call so we can update all the UI // efficiently: - // |text| is either the new temporary text from the user manually selecting - // a different match, or the inline autocomplete text. We distinguish by - // checking if |destination_for_temporary_text_change| is NULL. - // |destination_for_temporary_text_change| is NULL (if temporary text should - // not change) or the pre-change desitnation URL (if temporary text should - // change) so we can save it off to restore later. + // |text| is either the new temporary text (if |is_temporary_text| is true) + // from the user manually selecting a different match, or the inline + // autocomplete text (if |is_temporary_text| is false). // |keyword| is the keyword to show a hint for if |is_keyword_hint| is true, // or the currently selected keyword if |is_keyword_hint| is false (see // comments on keyword_ and is_keyword_hint_). + // |type| is the type of match selected; this is used to determine whether + // we can show the "Type to search" hint (see comments on + // show_search_hint_). void OnPopupDataChanged( const std::wstring& text, - GURL* destination_for_temporary_text_change, + bool is_temporary_text, const std::wstring& keyword, - bool is_keyword_hint); + bool is_keyword_hint, + AutocompleteMatch::Type type); // Called by the AutocompleteEditView after something changes, with details // about what state changes occured. Updates internal state, updates the @@ -321,10 +326,16 @@ class AutocompleteEditModel : public NotificationObserver { std::wstring DisplayTextFromUserText(const std::wstring& text) const; std::wstring UserTextFromDisplayText(const std::wstring& text) const; - // Returns the default match for the current text, as well as the alternate - // nav URL, if |alternate_nav_url| is non-NULL and there is such a URL. - void GetInfoForCurrentText(AutocompleteMatch* match, - GURL* alternate_nav_url) const; + // Returns the URL. If the user has not edited the text, this returns the + // permanent text. If the user has edited the text, this returns the default + // match based on the current text, which may be a search URL, or keyword + // generated URL. + // + // See AutocompleteEdit for a description of the args (they may be null if + // not needed). + GURL GetURLForCurrentText(PageTransition::Type* transition, + bool* is_history_what_you_typed_match, + GURL* alternate_nav_url) const; AutocompleteEditView* view_; @@ -421,6 +432,10 @@ class AutocompleteEditModel : public NotificationObserver { // See KeywordUIState enum. KeywordUIState keyword_ui_state_; + // True when it's safe to show a "Type to search" hint to the user (when the + // edit is empty, or the user is in the process of searching). + bool show_search_hint_; + // Paste And Go-related state. See CanPasteAndGo(). mutable GURL paste_and_go_url_; mutable PageTransition::Type paste_and_go_transition_; diff --git a/chrome/browser/autocomplete/autocomplete_edit_view.h b/chrome/browser/autocomplete/autocomplete_edit_view.h index 0d4c230..63c2524 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view.h @@ -59,13 +59,6 @@ class AutocompleteEditView { // browser, or just whatever the user has currently typed. virtual std::wstring GetText() const = 0; - // |true| if the user is in the process of editing the field, or if - // the field is empty. - virtual bool IsEditingOrEmpty() const = 0; - - // Returns the resource ID of the icon to show for the current text. - virtual int GetIcon() const = 0; - // The user text is the text the user has manually keyed in. When present, // this is shown in preference to the permanent text; hitting escape will // revert to the permanent text. diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc index 006395f..86d886d 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc @@ -17,6 +17,7 @@ #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/autocomplete/autocomplete_edit.h" #include "chrome/browser/autocomplete/autocomplete_popup_model.h" +#include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/command_updater.h" #include "chrome/browser/defaults.h" @@ -33,11 +34,9 @@ #include "net/base/escape.h" #if defined(TOOLKIT_VIEWS) -#include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h" #include "chrome/browser/views/location_bar_view.h" #include "gfx/skia_utils_gtk.h" #else -#include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h" #include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/browser/gtk/location_bar_view_gtk.h" #endif @@ -46,13 +45,11 @@ using gfx::SkColorToGdkColor; namespace { -const gchar* kAutocompleteEditViewGtkKey = "__ACE_VIEW_GTK__"; - const char kTextBaseColor[] = "#808080"; -const char kSecureSchemeColor[] = "#079500"; -const char kSecurityErrorSchemeColor[] = "#a20000"; +const char kSecureSchemeColor[] = "#009614"; +const char kInsecureSchemeColor[] = "#c80000"; -const double kStrikethroughStrokeRed = 162.0 / 256.0; +const double kStrikethroughStrokeRed = 210.0 / 256.0; const double kStrikethroughStrokeWidth = 2.0; size_t GetUTF8Offset(const std::wstring& wide_text, size_t wide_text_offset) { @@ -111,26 +108,6 @@ void SetEntryStyle() { "style \"chrome-location-bar-entry\""); } -// Copied from GTK+. Called when we lose the primary selection. This will clear -// the selection in the text buffer. -void ClipboardSelectionCleared(GtkClipboard* clipboard, - gpointer data) { - GtkTextIter insert; - GtkTextIter selection_bound; - GtkTextBuffer* buffer = GTK_TEXT_BUFFER(data); - - gtk_text_buffer_get_iter_at_mark(buffer, &insert, - gtk_text_buffer_get_insert(buffer)); - gtk_text_buffer_get_iter_at_mark(buffer, &selection_bound, - gtk_text_buffer_get_selection_bound(buffer)); - - if (!gtk_text_iter_equal(&insert, &selection_bound)) { - gtk_text_buffer_move_mark(buffer, - gtk_text_buffer_get_selection_bound(buffer), - &insert); - } -} - } // namespace AutocompleteEditViewGtk::AutocompleteEditViewGtk( @@ -139,30 +116,23 @@ AutocompleteEditViewGtk::AutocompleteEditViewGtk( Profile* profile, CommandUpdater* command_updater, bool popup_window_mode, -#if defined(TOOLKIT_VIEWS) - const views::View* location_bar) -#else - GtkWidget* location_bar) -#endif + const BubblePositioner* bubble_positioner) : text_view_(NULL), tag_table_(NULL), text_buffer_(NULL), faded_text_tag_(NULL), secure_scheme_tag_(NULL), - security_error_scheme_tag_(NULL), + insecure_scheme_tag_(NULL), model_(new AutocompleteEditModel(this, controller, profile)), -#if defined(TOOLKIT_VIEWS) - popup_view_(new AutocompletePopupContentsView( - gfx::Font(), this, model_.get(), profile, location_bar)), -#else - popup_view_(new AutocompletePopupViewGtk(this, model_.get(), profile, - location_bar)), -#endif + popup_view_(AutocompletePopupView::CreatePopupView(gfx::Font(), this, + model_.get(), + profile, + bubble_positioner)), controller_(controller), toolbar_model_(toolbar_model), command_updater_(command_updater), popup_window_mode_(popup_window_mode), - security_level_(ToolbarModel::NONE), + scheme_security_level_(ToolbarModel::NORMAL), mark_set_handler_id_(0), #if defined(OS_CHROMEOS) button_1_pressed_(false), @@ -215,7 +185,6 @@ void AutocompleteEditViewGtk::Init() { // the other objects adds a reference; it doesn't adopt them. tag_table_ = gtk_text_tag_table_new(); text_buffer_ = gtk_text_buffer_new(tag_table_); - g_object_set_data(G_OBJECT(text_buffer_), kAutocompleteEditViewGtkKey, this); text_view_ = gtk_text_view_new_with_buffer(text_buffer_); if (popup_window_mode_) gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view_), false); @@ -246,8 +215,8 @@ void AutocompleteEditViewGtk::Init() { NULL, "foreground", kTextBaseColor, NULL); secure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, NULL, "foreground", kSecureSchemeColor, NULL); - security_error_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, - NULL, "foreground", kSecurityErrorSchemeColor, NULL); + insecure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, + NULL, "foreground", kInsecureSchemeColor, NULL); normal_text_tag_ = gtk_text_buffer_create_tag(text_buffer_, NULL, "foreground", "#000000", NULL); @@ -289,8 +258,6 @@ void AutocompleteEditViewGtk::Init() { G_CALLBACK(&HandlePopulatePopupThunk), this); mark_set_handler_id_ = g_signal_connect( text_buffer_, "mark-set", G_CALLBACK(&HandleMarkSetThunk), this); - mark_set_handler_id2_ = g_signal_connect_after( - text_buffer_, "mark-set", G_CALLBACK(&HandleMarkSetAfterThunk), this); g_signal_connect(text_view_, "drag-data-received", G_CALLBACK(&HandleDragDataReceivedThunk), this); g_signal_connect(text_view_, "backspace", @@ -317,7 +284,7 @@ void AutocompleteEditViewGtk::Init() { SetBaseColor(); #endif - ViewIDUtil::SetID(GetNativeView(), VIEW_ID_AUTOCOMPLETE); + ViewIDUtil::SetID(widget(), VIEW_ID_AUTOCOMPLETE); } void AutocompleteEditViewGtk::SetFocus() { @@ -351,8 +318,9 @@ void AutocompleteEditViewGtk::SaveStateToTab(TabContents* tab) { DCHECK(tab); // If any text has been selected, register it as the PRIMARY selection so it // can still be pasted via middle-click after the text view is cleared. - if (!selected_text_.empty()) + if (!selected_text_.empty()) { SavePrimarySelection(selected_text_); + } // NOTE: GetStateForTabSwitch may affect GetSelection, so order is important. AutocompleteEditModel::State model_state = model_->GetStateForTabSwitch(); GetStateAccessor()->SetProperty( @@ -366,9 +334,15 @@ void AutocompleteEditViewGtk::Update(const TabContents* contents) { model_->UpdatePermanentText(toolbar_model_->GetText()); ToolbarModel::SecurityLevel security_level = - toolbar_model_->GetSecurityLevel(); - bool changed_security_level = (security_level != security_level_); - security_level_ = security_level; + toolbar_model_->GetSchemeSecurityLevel(); + bool changed_security_level = (security_level != scheme_security_level_); + scheme_security_level_ = security_level; + + // TODO(deanm): This doesn't exactly match Windows. There there is a member + // background_color_. I think we can get away with just the level though. + if (changed_security_level) { + SetBaseColor(); + } if (contents) { selected_text_.clear(); @@ -418,17 +392,6 @@ std::wstring AutocompleteEditViewGtk::GetText() const { return out; } -bool AutocompleteEditViewGtk::IsEditingOrEmpty() const { - return model_->user_input_in_progress() || - (gtk_text_buffer_get_char_count(text_buffer_) == 0); -} - -int AutocompleteEditViewGtk::GetIcon() const { - return IsEditingOrEmpty() ? - AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) : - toolbar_model_->GetIcon(); -} - void AutocompleteEditViewGtk::SetUserText(const std::wstring& text, const std::wstring& display_text, bool update_popup) { @@ -619,8 +582,10 @@ void AutocompleteEditViewGtk::SetBaseColor() { bool use_gtk = theme_provider_->UseGtkTheme(); #endif - if (use_gtk) { - gtk_widget_modify_cursor(text_view_, NULL, NULL); + // If we're on a secure connection, ignore what the theme wants us to do + // and use a yellow background. + bool is_secure = (scheme_security_level_ == ToolbarModel::SECURE); + if (use_gtk && !is_secure) { gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, NULL); gtk_widget_modify_base(text_view_, GTK_STATE_SELECTED, NULL); gtk_widget_modify_text(text_view_, GTK_STATE_SELECTED, NULL); @@ -635,21 +600,20 @@ void AutocompleteEditViewGtk::SetBaseColor() { GdkColor average_color = gtk_util::AverageColors( style->text[GTK_STATE_NORMAL], style->base[GTK_STATE_NORMAL]); - g_object_set(faded_text_tag_, "foreground-gdk", &average_color, NULL); + g_object_set(faded_text_tag_, "foreground-gdk", + &average_color, NULL); g_object_set(normal_text_tag_, "foreground-gdk", &style->text[GTK_STATE_NORMAL], NULL); } else { - const GdkColor* background_color_ptr; #if defined(TOOLKIT_VIEWS) const GdkColor background_color = gfx::SkColorToGdkColor( - LocationBarView::GetColor(ToolbarModel::NONE, - LocationBarView::BACKGROUND)); - background_color_ptr = &background_color; + LocationBarView::GetColor(is_secure, LocationBarView::BACKGROUND)); + gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, + &background_color); #else - background_color_ptr = &LocationBarViewGtk::kBackgroundColor; + gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, + &LocationBarViewGtk::kBackgroundColorByLevel[scheme_security_level_]); #endif - gtk_widget_modify_cursor(text_view_, &gfx::kGdkBlack, &gfx::kGdkGray); - gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, background_color_ptr); #if !defined(TOOLKIT_VIEWS) // Override the selected colors so we don't leak colors from the current @@ -1073,32 +1037,11 @@ void AutocompleteEditViewGtk::HandleMarkSet(GtkTextBuffer* buffer, GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); if (gtk_clipboard_get_owner(clipboard) == G_OBJECT(text_buffer_)) SavePrimarySelection(selected_text_); - } else if (IsSelectAll() && !model_->user_input_in_progress()) { - // Copy the whole URL to the clipboard (including the scheme, which is - // hidden in the case of http://). - GURL url; - if (model_->GetURLForText(GetText(), &url)) - OwnPrimarySelection(url.spec()); } selected_text_ = new_selected_text; } -// Override the primary selection the text buffer has set. This has to happen -// after the default handler for the "mark-set" signal. -void AutocompleteEditViewGtk::HandleMarkSetAfter(GtkTextBuffer* buffer, - GtkTextIter* location, - GtkTextMark* mark) { - std::wstring text = GetText(); - if (IsSelectAll() && !model_->user_input_in_progress() && !text.empty()) { - // Copy the whole URL to the clipboard (including the scheme, which is - // hidden in the case of http://). - GURL url; - if (model_->GetURLForText(GetText(), &url)) - OwnPrimarySelection(url.spec()); - } -} - // Just use the default behavior for DnD, except if the drop can be a PasteAndGo // then override. void AutocompleteEditViewGtk::HandleDragDataReceived( @@ -1235,14 +1178,18 @@ void AutocompleteEditViewGtk::HandleCopyOrCutClipboard(GtkWidget* sender) { // string to avoid encoding and escaping issues when pasting this text // elsewhere. scw.WriteText(url_spec16); - OwnPrimarySelection(url.spec()); } else { scw.WriteText(text16); - OwnPrimarySelection(UTF16ToUTF8(text16)); } scw.WriteHyperlink(UTF16ToUTF8(EscapeForHTML(text16)), url.spec()); + // Update PRIMARY selection if it is not owned by the text_buffer. + if (gtk_clipboard_get_owner(clipboard) != G_OBJECT(text_buffer_)) { + std::string utf8_text(UTF16ToUTF8(text16)); + gtk_clipboard_set_text(clipboard, utf8_text.c_str(), utf8_text.length()); + } + // Stop propagating the signal. static guint signal_id = g_signal_lookup("copy-clipboard", GTK_TYPE_TEXT_VIEW); @@ -1250,27 +1197,16 @@ void AutocompleteEditViewGtk::HandleCopyOrCutClipboard(GtkWidget* sender) { return; } - OwnPrimarySelection(selected_text_); -} - -void AutocompleteEditViewGtk::OwnPrimarySelection(const std::string& text) { - primary_selection_text_ = text; - - GtkTargetList* list = gtk_target_list_new(NULL, 0); - gtk_target_list_add_text_targets(list, 0); - gint len; - GtkTargetEntry* entries = gtk_target_table_new_from_list(list, &len); - - // When |text_buffer_| is destroyed, it will clear the clipboard, hence - // we needn't worry about calling gtk_clipboard_clear(). - gtk_clipboard_set_with_owner(gtk_clipboard_get(GDK_SELECTION_PRIMARY), - entries, len, - ClipboardGetSelectionThunk, - ClipboardSelectionCleared, - G_OBJECT(text_buffer_)); + // Passing gtk_text_buffer_copy_clipboard() a text buffer that already owns + // the clipboard that's being updated clears the highlighted text, which we + // don't want to do (and it also appears to at least sometimes trigger a + // failed G_IS_OBJECT() assertion). + if (gtk_clipboard_get_owner(clipboard) == G_OBJECT(text_buffer_)) + return; - gtk_target_list_unref(list); - gtk_target_table_free(entries, len); + // We can't just call SavePrimarySelection(); that makes the text view lose + // the selection and unhighlight its text. + gtk_text_buffer_copy_clipboard(text_buffer_, clipboard); } void AutocompleteEditViewGtk::HandlePasteClipboard(GtkWidget* sender) { @@ -1358,7 +1294,6 @@ void AutocompleteEditViewGtk::StartUpdatingHighlightedText() { gtk_text_buffer_remove_selection_clipboard(text_buffer_, clipboard); } g_signal_handler_block(text_buffer_, mark_set_handler_id_); - g_signal_handler_block(text_buffer_, mark_set_handler_id2_); } void AutocompleteEditViewGtk::FinishUpdatingHighlightedText() { @@ -1370,7 +1305,6 @@ void AutocompleteEditViewGtk::FinishUpdatingHighlightedText() { gtk_text_buffer_add_selection_clipboard(text_buffer_, clipboard); } g_signal_handler_unblock(text_buffer_, mark_set_handler_id_); - g_signal_handler_unblock(text_buffer_, mark_set_handler_id2_); } AutocompleteEditViewGtk::CharRange AutocompleteEditViewGtk::GetSelection() { @@ -1440,21 +1374,22 @@ void AutocompleteEditViewGtk::EmphasizeURLComponents() { strikethrough_ = CharRange(); // Emphasize the scheme for security UI display purposes (if necessary). if (!model_->user_input_in_progress() && scheme.is_nonempty() && - (security_level_ != ToolbarModel::NONE)) { + (scheme_security_level_ != ToolbarModel::NORMAL)) { CharRange scheme_range = CharRange(GetUTF8Offset(text, scheme.begin), GetUTF8Offset(text, scheme.end())); ItersFromCharRange(scheme_range, &start, &end); - if (security_level_ == ToolbarModel::SECURITY_ERROR) { + if (scheme_security_level_ == ToolbarModel::SECURE) { + gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_, + &start, &end); + } else { strikethrough_ = scheme_range; // When we draw the strikethrough, we don't want to include the ':' at the // end of the scheme. strikethrough_.cp_max--; - gtk_text_buffer_apply_tag(text_buffer_, security_error_scheme_tag_, + gtk_text_buffer_apply_tag(text_buffer_, insecure_scheme_tag_, &start, &end); - } else { - gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_, &start, &end); } } } @@ -1534,23 +1469,3 @@ void AutocompleteEditViewGtk::HandleWidgetDirectionChanged( void AutocompleteEditViewGtk::HandleKeymapDirectionChanged(GdkKeymap* sender) { AdjustTextJustification(); } - -// static -void AutocompleteEditViewGtk::ClipboardGetSelectionThunk( - GtkClipboard* clipboard, - GtkSelectionData* selection_data, - guint info, - gpointer object) { - AutocompleteEditViewGtk* edit_view = - reinterpret_cast( - g_object_get_data(G_OBJECT(object), kAutocompleteEditViewGtkKey)); - edit_view->ClipboardGetSelection(clipboard, selection_data, info); -} - -void AutocompleteEditViewGtk::ClipboardGetSelection( - GtkClipboard* clipboard, - GtkSelectionData* selection_data, - guint info) { - gtk_selection_data_set_text(selection_data, primary_selection_text_.c_str(), - primary_selection_text_.size()); -} diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h index 66b837b..1eb1736 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -25,11 +25,9 @@ class AutocompleteEditController; class AutocompleteEditModel; class AutocompletePopupView; +class BubblePositioner; class Profile; class TabContents; -namespace views { -class View; -} #if !defined(TOOLKIT_VIEWS) class GtkThemeProvider; @@ -55,16 +53,14 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, Profile* profile, CommandUpdater* command_updater, bool popup_window_mode, -#if defined(TOOLKIT_VIEWS) - const views::View* location_bar); -#else - GtkWidget* location_bar); -#endif + const BubblePositioner* bubble_positioner); ~AutocompleteEditViewGtk(); // Initialize, create the underlying widgets, etc. void Init(); + GtkWidget* widget() { return alignment_.get(); } + // Returns the width, in pixels, needed to display the current text. The // returned value includes margins and borders. int TextWidth(); @@ -86,9 +82,6 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, virtual std::wstring GetText() const; - virtual bool IsEditingOrEmpty() const; - virtual int GetIcon() const; - virtual void SetUserText(const std::wstring& text) { SetUserText(text, text, true); } @@ -141,9 +134,6 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, GtkTextBuffer*); CHROMEG_CALLBACK_2(AutocompleteEditViewGtk, void, HandleMarkSet, GtkTextBuffer*, GtkTextIter*, GtkTextMark*); - // As above, but called after the default handler. - CHROMEG_CALLBACK_2(AutocompleteEditViewGtk, void, HandleMarkSetAfter, - GtkTextBuffer*, GtkTextIter*, GtkTextMark*); CHROMEG_CALLBACK_3(AutocompleteEditViewGtk, void, HandleInsertText, GtkTextBuffer*, GtkTextIter*, const gchar*, gint); CHROMEG_CALLBACK_0(AutocompleteEditViewGtk, void, @@ -182,20 +172,6 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, void, HandleWidgetDirectionChanged, GtkTextDirection); - // Callback for the PRIMARY selection clipboard. - static void ClipboardGetSelectionThunk(GtkClipboard* clipboard, - GtkSelectionData* selection_data, - guint info, - gpointer object); - void ClipboardGetSelection(GtkClipboard* clipboard, - GtkSelectionData* selection_data, - guint info); - - // Take control of the PRIMARY selection clipboard with |text|. Use - // |text_buffer_| as the owner, so that this doesn't remove the selection on - // it. This makes use of the above callbacks. - void OwnPrimarySelection(const std::string& text); - // Gets the GTK_TEXT_WINDOW_WIDGET coordinates for |text_view_| that bound the // given iters. gfx::Rect WindowBoundsFromIters(GtkTextIter* iter1, GtkTextIter* iter2); @@ -233,8 +209,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, // Internally invoked whenever the text changes in some way. void TextChanged(); - // Save |selected_text| as the PRIMARY X selection. Unlike - // OwnPrimarySelection(), this won't set an owner or use callbacks. + // Save |selected_text| as the PRIMARY X selection. void SavePrimarySelection(const std::string& selected_text); // Update the field with |text| and set the selection. @@ -264,7 +239,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, GtkTextBuffer* text_buffer_; GtkTextTag* faded_text_tag_; GtkTextTag* secure_scheme_tag_; - GtkTextTag* security_error_scheme_tag_; + GtkTextTag* insecure_scheme_tag_; GtkTextTag* normal_text_tag_; scoped_ptr model_; @@ -280,7 +255,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, // different presentation (smaller font size). This is used for popups. bool popup_window_mode_; - ToolbarModel::SecurityLevel security_level_; + ToolbarModel::SecurityLevel scheme_security_level_; // Selection at the point where the user started using the // arrows to move around in the popup. @@ -297,12 +272,8 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, // it, we pass this string to SavePrimarySelection()). std::string selected_text_; - // When we own the X clipboard, this is the text for it. - std::string primary_selection_text_; - - // IDs of the signal handlers for "mark-set" on |text_buffer_|. + // ID of the signal handler for "mark-set" on |text_buffer_|. gulong mark_set_handler_id_; - gulong mark_set_handler_id2_; #if defined(OS_CHROMEOS) // The following variables are used to implement select-all-on-mouse-up, which diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h index 80f18e8..11bb62f 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,6 +13,7 @@ class AutocompleteEditController; class AutocompletePopupViewMac; +class BubblePositioner; class Clipboard; class Profile; class ToolbarModel; @@ -23,6 +24,7 @@ class AutocompleteEditViewMac : public AutocompleteEditView, public AutocompleteTextFieldObserver { public: AutocompleteEditViewMac(AutocompleteEditController* controller, + const BubblePositioner* bubble_positioner, ToolbarModel* toolbar_model, Profile* profile, CommandUpdater* command_updater, @@ -46,10 +48,6 @@ class AutocompleteEditViewMac : public AutocompleteEditView, const std::wstring& keyword); virtual std::wstring GetText() const; - - virtual bool IsEditingOrEmpty() const; - virtual int GetIcon() const; - virtual void SetUserText(const std::wstring& text) { SetUserText(text, text, true); } @@ -100,10 +98,6 @@ class AutocompleteEditViewMac : public AutocompleteEditView, // empty string if no appropriate data is found on |clipboard|. static std::wstring GetClipboardText(Clipboard* clipboard); - // If |resource_id| has a PDF image which can be used, return it. - // Otherwise return the PNG image from the resource bundle. - static NSImage* ImageForResource(int resource_id); - private: // Called when the user hits backspace in |field_|. Checks whether // keyword search is being terminated. Returns true if the diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm index 61ff69dd..81a3daf 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm +++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm @@ -9,7 +9,6 @@ #include "app/clipboard/clipboard.h" #include "app/clipboard/scoped_clipboard_writer.h" #include "app/resource_bundle.h" -#include "base/nsimage_cache_mac.h" #include "base/string_util.h" #include "base/sys_string_conversions.h" #include "base/utf_string_conversions.h" @@ -21,7 +20,6 @@ #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/toolbar_model.h" #include "grit/generated_resources.h" -#include "grit/theme_resources.h" #include "net/base/escape.h" // Focus-handling between |field_| and |model_| is a bit subtle. @@ -63,6 +61,15 @@ const NSColor* ColorWithRGBBytes(int rr, int gg, int bb) { blue:static_cast(bb)/255.0 alpha:1.0]; } +const NSColor* SecureBackgroundColor() { + return ColorWithRGBBytes(255, 245, 195); // Yellow +} +const NSColor* NormalBackgroundColor() { + return [NSColor controlBackgroundColor]; +} +const NSColor* InsecureBackgroundColor() { + return [NSColor controlBackgroundColor]; +} const NSColor* HostTextColor() { return [NSColor blackColor]; @@ -70,14 +77,11 @@ const NSColor* HostTextColor() { const NSColor* BaseTextColor() { return [NSColor darkGrayColor]; } -const NSColor* EVSecureSchemeColor() { - return ColorWithRGBBytes(0x07, 0x95, 0x00); -} const NSColor* SecureSchemeColor() { - return ColorWithRGBBytes(0x00, 0x0e, 0x95); + return ColorWithRGBBytes(0x00, 0x96, 0x14); } -const NSColor* SecurityErrorSchemeColor() { - return ColorWithRGBBytes(0xa2, 0x00, 0x00); +const NSColor* InsecureSchemeColor() { + return ColorWithRGBBytes(0xc8, 0x00, 0x00); } // Store's the model and view state across tab switches. @@ -121,57 +125,20 @@ NSRange ComponentToNSRange(const url_parse::Component& component) { } // namespace -// static -NSImage* AutocompleteEditViewMac::ImageForResource(int resource_id) { - NSString* image_name = nil; - - switch(resource_id) { - // From the autocomplete popup, or the star icon at the RHS of the - // text field. - case IDR_OMNIBOX_STAR: image_name = @"omnibox_star.pdf"; break; - case IDR_OMNIBOX_STAR_LIT: image_name = @"omnibox_star_lit.pdf"; break; - - // Values from |AutocompleteMatch::TypeToIcon()|. - case IDR_OMNIBOX_SEARCH: image_name = @"omnibox_search.pdf"; break; - case IDR_OMNIBOX_HTTP: image_name = @"omnibox_http.pdf"; break; - case IDR_OMNIBOX_HISTORY: image_name = @"omnibox_history.pdf"; break; - case IDR_OMNIBOX_MORE: image_name = @"omnibox_more.pdf"; break; - - // Values from |ToolbarModel::GetIcon()|. - case IDR_OMNIBOX_HTTPS_VALID: - image_name = @"omnibox_https_valid.pdf"; break; - case IDR_OMNIBOX_HTTPS_WARNING: - image_name = @"omnibox_https_warning.pdf"; break; - case IDR_OMNIBOX_HTTPS_INVALID: - image_name = @"omnibox_https_invalid.pdf"; break; - } - - if (image_name) { - if (NSImage* image = nsimage_cache::ImageNamed(image_name)) { - return image; - } else { - NOTREACHED() - << "Missing image for " << base::SysNSStringToUTF8(image_name); - } - } - - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - return rb.GetNSImageNamed(resource_id); -} - // TODO(shess): AutocompletePopupViewMac doesn't really need an // NSTextField. It wants to know where the position the popup, what // font to use, and it also needs to be able to attach the popup to // the window |field_| is in. AutocompleteEditViewMac::AutocompleteEditViewMac( AutocompleteEditController* controller, + const BubblePositioner* bubble_positioner, ToolbarModel* toolbar_model, Profile* profile, CommandUpdater* command_updater, AutocompleteTextField* field) : model_(new AutocompleteEditModel(this, controller, profile)), - popup_view_(new AutocompletePopupViewMac(this, model_.get(), profile, - field)), + popup_view_(new AutocompletePopupViewMac( + this, model_.get(), bubble_positioner, profile, field)), controller_(controller), toolbar_model_(toolbar_model), command_updater_(command_updater), @@ -305,17 +272,6 @@ std::wstring AutocompleteEditViewMac::GetText() const { return base::SysNSStringToWide([field_ stringValue]); } -bool AutocompleteEditViewMac::IsEditingOrEmpty() const { - return model_->user_input_in_progress() || - ([[field_ stringValue] length] == 0); -} - -int AutocompleteEditViewMac::GetIcon() const { - return IsEditingOrEmpty() ? - AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) : - toolbar_model_->GetIcon(); -} - void AutocompleteEditViewMac::SetUserText(const std::wstring& text, const std::wstring& display_text, bool update_popup) { @@ -454,23 +410,32 @@ void AutocompleteEditViewMac::SetText(const std::wstring& display_text) { // TODO(shess): GTK has this as a member var, figure out why. // [Could it be to not change if no change? If so, I'm guessing // AppKit may already handle that.] - const ToolbarModel::SecurityLevel security_level = - toolbar_model_->GetSecurityLevel(); + const ToolbarModel::SecurityLevel scheme_security_level = + toolbar_model_->GetSchemeSecurityLevel(); + + if (scheme_security_level == ToolbarModel::SECURE) { + [field_ setBackgroundColor:SecureBackgroundColor()]; + } else if (scheme_security_level == ToolbarModel::NORMAL) { + [field_ setBackgroundColor:NormalBackgroundColor()]; + } else if (scheme_security_level == ToolbarModel::INSECURE) { + [field_ setBackgroundColor:InsecureBackgroundColor()]; + } else { + NOTREACHED() << "Unexpected scheme_security_level: " + << scheme_security_level; + } // Emphasize the scheme for security UI display purposes (if necessary). if (!model_->user_input_in_progress() && scheme.is_nonempty() && - (security_level != ToolbarModel::NONE)) { + (scheme_security_level != ToolbarModel::NORMAL)) { NSColor* color; - if (security_level == ToolbarModel::EV_SECURE) { - color = EVSecureSchemeColor(); - } else if (security_level == ToolbarModel::SECURITY_ERROR) { - color = SecurityErrorSchemeColor(); + if (scheme_security_level == ToolbarModel::SECURE) { + color = SecureSchemeColor(); + } else { + color = InsecureSchemeColor(); // Add a strikethrough through the scheme. [as addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:ComponentToNSRange(scheme)]; - } else { - color = SecureSchemeColor(); } [as addAttribute:NSForegroundColorAttributeName value:color range:ComponentToNSRange(scheme)]; diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc index 5a0632f..6ead1fe 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc @@ -28,6 +28,7 @@ #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/autocomplete/autocomplete_accessibility.h" #include "chrome/browser/autocomplete/autocomplete_popup_model.h" +#include "chrome/browser/autocomplete/autocomplete_popup_view.h" #include "chrome/browser/autocomplete/keyword_provider.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/command_updater.h" @@ -386,10 +387,10 @@ AutocompleteEditViewWin::AutocompleteEditViewWin( Profile* profile, CommandUpdater* command_updater, bool popup_window_mode, - const views::View* location_bar) + const BubblePositioner* bubble_positioner) : model_(new AutocompleteEditModel(this, controller, profile)), - popup_view_(new AutocompletePopupContentsView(font, this, model_.get(), - profile, location_bar)), + popup_view_(AutocompletePopupView::CreatePopupView( + font, this, model_.get(), profile, bubble_positioner)), controller_(controller), parent_view_(parent_view), toolbar_model_(toolbar_model), @@ -406,9 +407,8 @@ AutocompleteEditViewWin::AutocompleteEditViewWin( in_drag_(false), initiated_drag_(false), drop_highlight_position_(-1), - background_color_(skia::SkColorToCOLORREF(LocationBarView::GetColor( - ToolbarModel::NONE, LocationBarView::BACKGROUND))), - security_level_(ToolbarModel::NONE), + background_color_(0), + scheme_security_level_(ToolbarModel::NORMAL), text_object_model_(NULL) { // Dummy call to a function exported by riched20.dll to ensure it sets up an // import dependency on the dll. @@ -459,8 +459,6 @@ AutocompleteEditViewWin::AutocompleteEditViewWin( cf.yOffset = -font_y_adjustment_ * kTwipsPerPixel; SetDefaultCharFormat(cf); - SetBackgroundColor(background_color_); - // By default RichEdit has a drop target. Revoke it so that we can install our // own. Revoke takes care of deleting the existing one. RevokeDragDrop(m_hWnd); @@ -510,21 +508,30 @@ void AutocompleteEditViewWin::Update( model_->UpdatePermanentText(toolbar_model_->GetText()); const ToolbarModel::SecurityLevel security_level = - toolbar_model_->GetSecurityLevel(); - const bool changed_security_level = (security_level != security_level_); + toolbar_model_->GetSchemeSecurityLevel(); + const COLORREF background_color = + skia::SkColorToCOLORREF(LocationBarView::GetColor( + security_level == ToolbarModel::SECURE, LocationBarView::BACKGROUND)); + const bool changed_security_level = + (security_level != scheme_security_level_); // Bail early when no visible state will actually change (prevents an // unnecessary ScopedFreeze, and thus UpdateWindow()). - if (!changed_security_level && !visibly_changed_permanent_text && - !tab_for_state_restoring) + if ((background_color == background_color_) && !changed_security_level && + !visibly_changed_permanent_text && !tab_for_state_restoring) return; - // Update our local state as desired. We set security_level_ here so it will - // already be correct before we get to any RevertAll()s below and use it. - security_level_ = security_level; + // Update our local state as desired. We set scheme_security_level_ here so + // it will already be correct before we get to any RevertAll()s below and use + // it. + ScopedFreeze freeze(this, GetTextObjectModel()); + if (background_color_ != background_color) { + background_color_ = background_color; + SetBackgroundColor(background_color_); + } + scheme_security_level_ = security_level; // When we're switching to a new tab, restore its state, if any. - ScopedFreeze freeze(this, GetTextObjectModel()); if (tab_for_state_restoring) { // Make sure we reset our own state first. The new tab may not have any // saved state, or it may not have had input in progress, in which case we @@ -598,16 +605,6 @@ std::wstring AutocompleteEditViewWin::GetText() const { return str; } -bool AutocompleteEditViewWin::IsEditingOrEmpty() const { - return model_->user_input_in_progress() || (GetTextLength() == 0); -} - -int AutocompleteEditViewWin::GetIcon() const { - return IsEditingOrEmpty() ? - AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) : - toolbar_model_->GetIcon(); -} - void AutocompleteEditViewWin::SetUserText(const std::wstring& text, const std::wstring& display_text, bool update_popup) { @@ -1372,6 +1369,15 @@ void AutocompleteEditViewWin::OnKillFocus(HWND focus_wnd) { ScopedFreeze freeze(this, GetTextObjectModel()); DefWindowProc(WM_KILLFOCUS, reinterpret_cast(focus_wnd), 0); + // Hide the "Type to search" hint if necessary. We do this after calling + // DefWindowProc() because processing the resulting IME messages may notify + // the controller that input is in progress, which could cause the visible + // hints to change. (I don't know if there's a real scenario where they + // actually do change, but this is safest.) + if (model_->show_search_hint() || + (model_->is_keyword_hint() && !model_->keyword().empty())) + controller_->OnChanged(); + // Cancel any user selection and scroll the text back to the beginning of the // URL. We have to do this after calling DefWindowProc() because otherwise // an in-progress IME composition will be completed at the new caret position, @@ -1681,6 +1687,12 @@ void AutocompleteEditViewWin::OnSetFocus(HWND focus_wnd) { model_->OnSetFocus(GetKeyState(VK_CONTROL) < 0); + // Notify controller if it needs to show hint UI of some kind. + ScopedFreeze freeze(this, GetTextObjectModel()); + if (model_->show_search_hint() || + (model_->is_keyword_hint() && !model_->keyword().empty())) + controller_->OnChanged(); + // Restore saved selection if available. if (saved_selection_for_focus_change_.cpMin != -1) { SetSelectionRange(saved_selection_for_focus_change_); @@ -2048,11 +2060,11 @@ void AutocompleteEditViewWin::EmphasizeURLComponents() { // Set the baseline emphasis. CHARFORMAT cf = {0}; cf.dwMask = CFM_COLOR; + const bool is_secure = (scheme_security_level_ == ToolbarModel::SECURE); // If we're going to emphasize parts of the text, then the baseline state // should be "de-emphasized". If not, then everything should be rendered in // the standard text color. - cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor( - security_level_, + cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor(is_secure, emphasize ? LocationBarView::DEEMPHASIZED_TEXT : LocationBarView::TEXT)); // NOTE: Don't use SetDefaultCharFormat() instead of the below; that sets the // format that will get applied to text added in the future, not to text @@ -2063,7 +2075,7 @@ void AutocompleteEditViewWin::EmphasizeURLComponents() { if (emphasize) { // We've found a host name, give it more emphasis. cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor( - security_level_, LocationBarView::TEXT)); + is_secure, LocationBarView::TEXT)); SetSelection(host.begin, host.end()); SetSelectionCharFormat(cf); } @@ -2071,13 +2083,13 @@ void AutocompleteEditViewWin::EmphasizeURLComponents() { // Emphasize the scheme for security UI display purposes (if necessary). insecure_scheme_component_.reset(); if (!model_->user_input_in_progress() && scheme.is_nonempty() && - (security_level_ != ToolbarModel::NONE)) { - if (security_level_ == ToolbarModel::SECURITY_ERROR) { + (scheme_security_level_ != ToolbarModel::NORMAL)) { + if (!is_secure) { insecure_scheme_component_.begin = scheme.begin; insecure_scheme_component_.len = scheme.len; } cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor( - security_level_, LocationBarView::SECURITY_TEXT)); + is_secure, LocationBarView::SECURITY_TEXT)); SetSelection(scheme.begin, scheme.end()); SetSelectionCharFormat(cf); } @@ -2171,8 +2183,8 @@ void AutocompleteEditViewWin::DrawSlashForInsecureScheme( canvas.save(); if (selection_rect.isEmpty() || canvas.clipRect(selection_rect, SkRegion::kDifference_Op)) { - paint.setColor(LocationBarView::GetColor(security_level_, - LocationBarView::SECURITY_TEXT)); + paint.setColor(LocationBarView::GetColor(false, + LocationBarView::SCHEME_STRIKEOUT)); canvas.drawLine(start_point.fX, start_point.fY, end_point.fX, end_point.fY, paint); } @@ -2180,7 +2192,7 @@ void AutocompleteEditViewWin::DrawSlashForInsecureScheme( // Draw the selected portion of the stroke. if (!selection_rect.isEmpty() && canvas.clipRect(selection_rect)) { - paint.setColor(LocationBarView::GetColor(security_level_, + paint.setColor(LocationBarView::GetColor(false, LocationBarView::SELECTED_TEXT)); canvas.drawLine(start_point.fX, start_point.fY, end_point.fX, end_point.fY, paint); diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.h b/chrome/browser/autocomplete/autocomplete_edit_view_win.h index 33af6a7..9de2d34 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.h @@ -69,7 +69,7 @@ class AutocompleteEditViewWin Profile* profile, CommandUpdater* command_updater, bool popup_window_mode, - const views::View* location_bar); + const BubblePositioner* bubble_positioner); ~AutocompleteEditViewWin(); views::View* parent_view() const { return parent_view_; } @@ -91,9 +91,6 @@ class AutocompleteEditViewWin virtual std::wstring GetText() const; - virtual bool IsEditingOrEmpty() const; - virtual int GetIcon() const; - virtual void SetUserText(const std::wstring& text) { SetUserText(text, text, true); } @@ -479,7 +476,7 @@ class AutocompleteEditViewWin // Security UI-related data. COLORREF background_color_; - ToolbarModel::SecurityLevel security_level_; + ToolbarModel::SecurityLevel scheme_security_level_; // This interface is useful for accessing the CRichEditCtrl at a low level. mutable ITextDocument* text_object_model_; diff --git a/chrome/browser/autocomplete/autocomplete_popup_model.cc b/chrome/browser/autocomplete/autocomplete_popup_model.cc index 009cc0b..41e0255 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_model.cc +++ b/chrome/browser/autocomplete/autocomplete_popup_model.cc @@ -103,24 +103,12 @@ void AutocompletePopupModel::SetSelectedLine(size_t line, if (line == selected_line_) return; // Nothing else to do. - // We need to update |selected_line_| before calling OnPopupDataChanged(), so - // that when the edit notifies its controller that something has changed, the - // controller can get the correct updated data. - // - // NOTE: We should never reach here with no selected line; the same code that - // opened the popup and made it possible to get here should have also set a - // selected line. - CHECK(selected_line_ != kNoMatch); - GURL current_destination(result.match_at(selected_line_).destination_url); - view_->InvalidateLine(selected_line_); - selected_line_ = line; - view_->InvalidateLine(selected_line_); - // Update the edit with the new data for this match. // TODO(pkasting): If |selected_line_| moves to the controller, this can be // eliminated and just become a call to the observer on the edit. std::wstring keyword; const bool is_keyword_hint = GetKeywordForMatch(match, &keyword); + if (reset_to_default) { std::wstring inline_autocomplete_text; if ((match.inline_autocomplete_offset != std::wstring::npos) && @@ -128,15 +116,27 @@ void AutocompletePopupModel::SetSelectedLine(size_t line, inline_autocomplete_text = match.fill_into_edit.substr(match.inline_autocomplete_offset); } - edit_model_->OnPopupDataChanged(inline_autocomplete_text, NULL, - keyword, is_keyword_hint); + edit_model_->OnPopupDataChanged(inline_autocomplete_text, false, + keyword, is_keyword_hint, match.type); } else { - edit_model_->OnPopupDataChanged(match.fill_into_edit, ¤t_destination, - keyword, is_keyword_hint); + edit_model_->OnPopupDataChanged(match.fill_into_edit, true, + keyword, is_keyword_hint, match.type); } // Repaint old and new selected lines immediately, so that the edit doesn't - // appear to update [much] faster than the popup. + // appear to update [much] faster than the popup. We must not update + // |selected_line_| before calling OnPopupDataChanged() (since the edit may + // call us back to get data about the old selection), and we must not call + // UpdateWindow() before updating |selected_line_| (since the paint routine + // relies on knowing the correct selected line). + // + // NOTE: We should never reach here with no selected line; the same code that + // opened the popup and made it possible to get here should have also set a + // selected line. + CHECK(selected_line_ != kNoMatch); + view_->InvalidateLine(selected_line_); + selected_line_ = line; + view_->InvalidateLine(selected_line_); view_->PaintUpdatesNow(); } @@ -147,21 +147,22 @@ void AutocompletePopupModel::ResetToDefaultMatch() { view_->OnDragCanceled(); } -void AutocompletePopupModel::InfoForCurrentSelection( - AutocompleteMatch* match, +GURL AutocompletePopupModel::URLsForCurrentSelection( + PageTransition::Type* transition, + bool* is_history_what_you_typed_match, GURL* alternate_nav_url) const { - DCHECK(match != NULL); const AutocompleteResult* result; + AutocompleteResult::const_iterator match; if (!controller_->done()) { result = &controller_->latest_result(); // It's technically possible for |result| to be empty if no provider returns // a synchronous result but the query has not completed synchronously; // pratically, however, that should never actually happen. if (result->empty()) - return; + return GURL(); // The user cannot have manually selected a match, or the query would have // stopped. So the default match must be the desired selection. - *match = *result->default_match(); + match = result->default_match(); } else { CHECK(IsOpen()); // The query isn't running, so the standard result set can't possibly be out @@ -176,10 +177,15 @@ void AutocompletePopupModel::InfoForCurrentSelection( // called instead. CHECK(!result->empty()); CHECK(selected_line_ < result->size()); - *match = result->match_at(selected_line_); + match = result->begin() + selected_line_; } + if (transition) + *transition = match->transition; + if (is_history_what_you_typed_match) + *is_history_what_you_typed_match = match->is_history_what_you_typed_match; if (alternate_nav_url && manually_selected_match_.empty()) *alternate_nav_url = result->alternate_nav_url(); + return match->destination_url; } bool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match, @@ -233,7 +239,7 @@ void AutocompletePopupModel::Move(int count) { } void AutocompletePopupModel::TryDeletingCurrentItem() { - // We could use InfoForCurrentSelection() here, but it seems better to try + // We could use URLsForCurrentSelection() here, but it seems better to try // and shift-delete the actual selection, rather than any "in progress, not // yet visible" one. if (selected_line_ == kNoMatch) diff --git a/chrome/browser/autocomplete/autocomplete_popup_model.h b/chrome/browser/autocomplete/autocomplete_popup_model.h index a986419..166a238 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_model.h +++ b/chrome/browser/autocomplete/autocomplete_popup_model.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -73,9 +73,15 @@ class AutocompletePopupModel : public NotificationObserver { // will change the selected line back to the default match and redraw. void ResetToDefaultMatch(); - // Copies the selected match into |match|. If an update is in progress, - // "selected" means "default in the latest matches". If there are no matches, - // does not update |match|. + // Returns the URL for the selected match. If an update is in progress, + // "selected" means "default in the latest matches". If there are no + // matches, returns the empty string. + // + // If |transition_type| is non-NULL, it will be set to the appropriate + // transition type for the selected entry (TYPED or GENERATED). + // + // If |is_history_what_you_typed_match| is non-NULL, it will be set based on + // the selected entry's is_history_what_you_typed value. // // If |alternate_nav_url| is non-NULL, it will be set to the alternate // navigation URL for |url| if one exists, or left unchanged otherwise. See @@ -83,8 +89,10 @@ class AutocompletePopupModel : public NotificationObserver { // // TODO(pkasting): When manually_selected_match_ moves to the controller, this // can move too. - void InfoForCurrentSelection(AutocompleteMatch* match, - GURL* alternate_nav_url) const; + GURL URLsForCurrentSelection( + PageTransition::Type* transition, + bool* is_history_what_you_typed_match, + GURL* alternate_nav_url) const; // Gets the selected keyword or keyword hint for the given match. Returns // true if |keyword| represents a keyword hint, or false if |keyword| diff --git a/chrome/browser/autocomplete/autocomplete_popup_view.h b/chrome/browser/autocomplete/autocomplete_popup_view.h index 5674e4b..41b21a6 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_view.h +++ b/chrome/browser/autocomplete/autocomplete_popup_view.h @@ -13,7 +13,15 @@ #include "build/build_config.h" +class AutocompleteEditView; class AutocompletePopupModel; +class BubblePositioner; +namespace gfx { +class Font; +} +class AutocompleteEditViewWin; +class AutocompleteEditModel; +class Profile; class AutocompletePopupView { public: @@ -40,6 +48,17 @@ class AutocompletePopupView { // Returns the popup's model. virtual AutocompletePopupModel* GetModel() = 0; + +#if !defined(OS_MACOSX) + // Create a popup view implementation. It may make sense for this to become + // platform independent eventually. + static AutocompletePopupView* CreatePopupView( + const gfx::Font& font, + AutocompleteEditView* edit_view, + AutocompleteEditModel* edit_model, + Profile* profile, + const BubblePositioner* bubble_positioner); +#endif }; #endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_H_ diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc index 46a2115..84538e0f 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc +++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -18,18 +18,16 @@ #include "chrome/browser/autocomplete/autocomplete_edit.h" #include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" #include "chrome/browser/autocomplete/autocomplete_popup_model.h" +#include "chrome/browser/bubble_positioner.h" #include "chrome/browser/defaults.h" -#include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/browser/gtk/gtk_util.h" #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/common/notification_service.h" -#include "gfx/color_utils.h" #include "gfx/font.h" #include "gfx/gtk_util.h" #include "gfx/rect.h" -#include "gfx/skia_utils_gtk.h" #include "grit/theme_resources.h" namespace { @@ -46,40 +44,27 @@ const GdkColor kDescriptionSelectedTextColor = GDK_COLOR_RGB(0x78, 0x82, 0xb1); // We have a 1 pixel border around the entire results popup. const int kBorderThickness = 1; - // The vertical height of each result. const int kHeightPerResult = 24; - // Width of the icons. -const int kIconWidth = 17; - +const int kIconWidth = 16; // We want to vertically center the image in the result space. -const int kIconTopPadding = 2; - +const int kIconTopPadding = 4; // Space between the left edge (including the border) and the text. -const int kIconLeftPadding = 5 + kBorderThickness; - -// Space between the image and the text. -const int kIconRightPadding = 7; - +const int kIconLeftPadding = 6 + kBorderThickness; +// Space between the image and the text. Would be 6 to line up with the +// entry, but nudge it a bit more to match with the text in the entry. +const int kIconRightPadding = 10; // Space between the left edge (including the border) and the text. const int kIconAreaWidth = kIconLeftPadding + kIconWidth + kIconRightPadding; - // Space between the right edge (including the border) and the text. const int kRightPadding = 3; - // When we have both a content and description string, we don't want the // content to push the description off. Limit the content to a percentage of // the total width. const float kContentWidthPercentage = 0.7; -// How much to offset the popup from the bottom of the location bar in gtk mode. -const int kGtkVerticalOffset = 3; - -// How much we shrink the popup on the left/right in gtk mode. -const int kGtkHorizontalOffset = 1; - // UTF-8 Left-to-right embedding. const char* kLRE = "\xe2\x80\xaa"; @@ -118,7 +103,6 @@ void SetupLayoutForMatch(PangoLayout* layout, const std::wstring& text, AutocompleteMatch::ACMatchClassifications classifications, const GdkColor* base_color, - const GdkColor* url_color, const std::string& prefix_text) { // We can have a prefix, or insert additional characters while processing the @@ -155,7 +139,7 @@ void SetupLayoutForMatch(PangoLayout* layout, // support it. const GdkColor* color = base_color; if (i->style & ACMatchClassification::URL) { - color = url_color; + color = &kURLTextColor; // Insert a left to right embedding to make sure that URLs are shown LTR. std::string lre(kLRE); text_utf8.insert(offset, lre); @@ -180,81 +164,48 @@ void SetupLayoutForMatch(PangoLayout* layout, pango_attr_list_unref(attrs); } -GdkPixbuf* IconForMatch(BrowserThemeProvider* theme, - const AutocompleteMatch& match, - bool selected) { - int icon = match.starred ? - IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match.type); - if (selected) { - switch (icon) { - case IDR_OMNIBOX_HTTP: icon = IDR_OMNIBOX_HTTP_DARK; break; - case IDR_OMNIBOX_HISTORY: icon = IDR_OMNIBOX_HISTORY_DARK; break; - case IDR_OMNIBOX_SEARCH: icon = IDR_OMNIBOX_SEARCH_DARK; break; - case IDR_OMNIBOX_MORE: icon = IDR_OMNIBOX_MORE_DARK; break; - case IDR_OMNIBOX_STAR: icon = IDR_OMNIBOX_STAR_DARK; break; - default: NOTREACHED(); break; - } - } - +GdkPixbuf* IconForMatch(const AutocompleteMatch& match, bool selected) { + // TODO(deanm): These would be better as pixmaps someday. // TODO(estade): Do we want to flip these for RTL? (Windows doesn't). - return theme->GetPixbufNamed(icon); -} - -// Generates the normal URL color, a green color used in unhighlighted URL -// text. It is a mix of |kURLTextColor| and the current text color. Unlike the -// selected text color, It is more important to match the qualities of the -// foreground typeface color instead of taking the background into account. -GdkColor NormalURLColor(GdkColor foreground) { - color_utils::HSL fg_hsl; - color_utils::SkColorToHSL(gfx::GdkColorToSkColor(foreground), &fg_hsl); - - color_utils::HSL hue_hsl; - color_utils::SkColorToHSL(gfx::GdkColorToSkColor(kURLTextColor), &hue_hsl); - - // Only allow colors that have a fair amount of saturation in them (color vs - // white). This means that our output color will always be fairly green. - double s = std::max(0.5, fg_hsl.s); - - // Make sure the luminance is at least as bright as the |kURLTextColor| green - // would be if we were to use that. - double l; - if (fg_hsl.l < hue_hsl.l) - l = hue_hsl.l; - else - l = (fg_hsl.l + hue_hsl.l) / 2; - - color_utils::HSL output = { hue_hsl.h, s, l }; - return gfx::SkColorToGdkColor(color_utils::HSLToSkColor(output, 255)); -} + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + static GdkPixbuf* o2_globe = rb.GetPixbufNamed(IDR_O2_GLOBE); + static GdkPixbuf* o2_globe_s = rb.GetPixbufNamed(IDR_O2_GLOBE_SELECTED_DARK); + static GdkPixbuf* o2_history = rb.GetPixbufNamed(IDR_O2_HISTORY); + static GdkPixbuf* o2_history_s = + rb.GetPixbufNamed(IDR_O2_HISTORY_SELECTED_DARK); + static GdkPixbuf* o2_more = rb.GetPixbufNamed(IDR_O2_MORE); + static GdkPixbuf* o2_more_s = rb.GetPixbufNamed(IDR_O2_MORE_SELECTED_DARK); + static GdkPixbuf* o2_search = rb.GetPixbufNamed(IDR_O2_SEARCH); + static GdkPixbuf* o2_search_s = + rb.GetPixbufNamed(IDR_O2_SEARCH_SELECTED_DARK); + static GdkPixbuf* o2_star = rb.GetPixbufNamed(IDR_O2_STAR); + static GdkPixbuf* o2_star_s = rb.GetPixbufNamed(IDR_O2_STAR_SELECTED_DARK); + + if (match.starred) + return selected ? o2_star_s : o2_star; + + switch (match.type) { + case AutocompleteMatch::URL_WHAT_YOU_TYPED: + case AutocompleteMatch::NAVSUGGEST: + return selected ? o2_globe_s : o2_globe; + case AutocompleteMatch::HISTORY_URL: + case AutocompleteMatch::HISTORY_TITLE: + case AutocompleteMatch::HISTORY_BODY: + case AutocompleteMatch::HISTORY_KEYWORD: + return selected ? o2_history_s : o2_history; + case AutocompleteMatch::SEARCH_WHAT_YOU_TYPED: + case AutocompleteMatch::SEARCH_HISTORY: + case AutocompleteMatch::SEARCH_SUGGEST: + case AutocompleteMatch::SEARCH_OTHER_ENGINE: + return selected ? o2_search_s : o2_search; + case AutocompleteMatch::OPEN_HISTORY_PAGE: + return selected ? o2_more_s : o2_more; + default: + NOTREACHED(); + break; + } -// Generates the selected URL color, a green color used on URL text in the -// currently highlighted entry in the autocomplete popup. It's a mix of -// |kURLTextColor|, the current text color, and the background color (the -// select highlight). It is more important to contrast with the background -// saturation than to look exactly like the foreground color. -GdkColor SelectedURLColor(GdkColor foreground, GdkColor background) { - color_utils::HSL fg_hsl; - color_utils::SkColorToHSL(gfx::GdkColorToSkColor(foreground), &fg_hsl); - - color_utils::HSL bg_hsl; - color_utils::SkColorToHSL(gfx::GdkColorToSkColor(background), &bg_hsl); - - color_utils::HSL hue_hsl; - color_utils::SkColorToHSL(gfx::GdkColorToSkColor(kURLTextColor), &hue_hsl); - - // The saturation of the text should be opposite of the background, clamped - // to 0.2-0.8. We make sure it's greater than 0.2 so there's some color, but - // less than 0.8 so it's not the oversaturated neon-color. - double opposite_s = 1 - bg_hsl.s; - double s = std::max(0.2, std::min(0.8, opposite_s)); - - // The luminance should match the luminance of the foreground text. Again, - // we clamp so as to have at some amount of color (green) in the text. - double opposite_l = fg_hsl.l; - double l = std::max(0.1, std::min(0.9, opposite_l)); - - color_utils::HSL output = { hue_hsl.h, s, l }; - return gfx::SkColorToGdkColor(color_utils::HSLToSkColor(output, 255)); + return NULL; } } // namespace @@ -263,13 +214,12 @@ AutocompletePopupViewGtk::AutocompletePopupViewGtk( AutocompleteEditView* edit_view, AutocompleteEditModel* edit_model, Profile* profile, - GtkWidget* location_bar) + const BubblePositioner* bubble_positioner) : model_(new AutocompletePopupModel(this, edit_model, profile)), edit_view_(edit_view), - location_bar_(location_bar), + bubble_positioner_(bubble_positioner), window_(gtk_window_new(GTK_WINDOW_POPUP)), layout_(NULL), - theme_provider_(GtkThemeProvider::GetFrom(profile)), opened_(false) { GTK_WIDGET_UNSET_FLAGS(window_, GTK_CAN_FOCUS); // Don't allow the window to be resized. This also forces the window to @@ -278,6 +228,8 @@ AutocompletePopupViewGtk::AutocompletePopupViewGtk( gtk_widget_set_app_paintable(window_, TRUE); // Have GTK double buffer around the expose signal. gtk_widget_set_double_buffered(window_, TRUE); + // Set the background color, so we don't need to paint it manually. + gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &kBackgroundColor); // Cache the layout so we don't have to create it for every expose. If we // were a real widget we should handle changing directions, but we're not @@ -310,11 +262,6 @@ AutocompletePopupViewGtk::AutocompletePopupViewGtk( g_signal_connect(window_, "expose-event", G_CALLBACK(&HandleExposeThunk), this); - registrar_.Add(this, - NotificationType::BROWSER_THEME_CHANGED, - NotificationService::AllSources()); - theme_provider_->InitThemesFor(this); - // TODO(erg): There appears to be a bug somewhere in something which shows // itself when we're in NX. Previously, we called // gtk_util::ActAsRoundedWindow() to make this popup have rounded @@ -365,85 +312,16 @@ AutocompletePopupModel* AutocompletePopupViewGtk::GetModel() { return model_.get(); } -void AutocompletePopupViewGtk::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - DCHECK(type == NotificationType::BROWSER_THEME_CHANGED); - - if (theme_provider_->UseGtkTheme()) { - border_color_ = theme_provider_->GetBorderColor(); - - // Create a fake gtk table - GtkWidget* fake_tree = gtk_entry_new(); - GtkStyle* style = gtk_rc_get_style(fake_tree); - - background_color_ = style->base[GTK_STATE_NORMAL]; - selected_background_color_ = style->base[GTK_STATE_SELECTED]; - hovered_background_color_ = gtk_util::AverageColors( - background_color_, selected_background_color_); - - content_text_color_ = style->text[GTK_STATE_NORMAL]; - selected_content_text_color_ = style->text[GTK_STATE_SELECTED]; - url_text_color_ = - NormalURLColor(style->text[GTK_STATE_NORMAL]); - url_selected_text_color_ = - SelectedURLColor(style->text[GTK_STATE_SELECTED], - style->base[GTK_STATE_SELECTED]); - - description_text_color_ = style->text[GTK_STATE_NORMAL]; - description_selected_text_color_ = style->text[GTK_STATE_SELECTED]; - - g_object_ref_sink(fake_tree); - g_object_unref(fake_tree); - } else { - border_color_ = kBorderColor; - background_color_ = kBackgroundColor; - selected_background_color_ = kSelectedBackgroundColor; - hovered_background_color_ = kHoveredBackgroundColor; - - content_text_color_ = kContentTextColor; - selected_content_text_color_ = kContentTextColor; - url_text_color_ = kURLTextColor; - url_selected_text_color_ = kURLTextColor; - description_text_color_ = kDescriptionTextColor; - description_selected_text_color_ = kDescriptionSelectedTextColor; - } - - // Set the background color, so we don't need to paint it manually. - gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &background_color_); -} - void AutocompletePopupViewGtk::Show(size_t num_results) { - gint origin_x, origin_y; - gdk_window_get_origin(location_bar_->window, &origin_x, &origin_y); - GtkAllocation allocation = location_bar_->allocation; - int vertical_offset = 0; - int horizontal_offset = 0; - if (theme_provider_->UseGtkTheme()) { - // Shrink the popup by 1 pixel on both sides in gtk mode. The darkest line - // is usually one pixel in, and is almost always +/-1 pixel from this, - // meaning the vertical offset will hide (hopefully) problems when this is - // wrong. - horizontal_offset = kGtkHorizontalOffset; - - // We offset the the popup from the bottom of the location bar in gtk - // mode. The background color between the bottom of the location bar and - // the popup helps hide the fact that we can't really reliably match what - // the user would otherwise preceive as the left/right edges of the - // location bar. - vertical_offset = kGtkVerticalOffset; - } - - gtk_window_move(GTK_WINDOW(window_), - origin_x + allocation.x - kBorderThickness + horizontal_offset, - origin_y + allocation.y + allocation.height - kBorderThickness - 1 + - vertical_offset); - gtk_widget_set_size_request(window_, - allocation.width + (kBorderThickness * 2) - (horizontal_offset * 2), - (num_results * kHeightPerResult) + (kBorderThickness * 2)); - gtk_widget_show(window_); - StackWindow(); - opened_ = true; + gfx::Rect rect = bubble_positioner_->GetLocationStackBounds(); + rect.set_y(rect.bottom()); + rect.set_height((num_results * kHeightPerResult) + (kBorderThickness * 2)); + + gtk_window_move(GTK_WINDOW(window_), rect.x(), rect.y()); + gtk_widget_set_size_request(window_, rect.width(), rect.height()); + gtk_widget_show(window_); + StackWindow(); + opened_ = true; } void AutocompletePopupViewGtk::Hide() { @@ -536,7 +414,7 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget, GdkGC* gc = gdk_gc_new(drawable); // kBorderColor is unallocated, so use the GdkRGB routine. - gdk_gc_set_rgb_fg_color(gc, &border_color_); + gdk_gc_set_rgb_fg_color(gc, &kBorderColor); // This assert is kinda ugly, but it would be more currently unneeded work // to support painting a border that isn't 1 pixel thick. There is no point @@ -549,17 +427,8 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget, pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE); - // An offset to align text in gtk mode. The hard coded constants in this file - // are all created for the chrome-theme. In an effort to make this look good - // on the majority of gtk themes, we shrink the popup by one pixel on each - // side and push it downwards a bit so there's space between the drawn - // location bar and the popup so we don't touch it (contrast with - // chrome-theme where that's exactly what we want). Because of that, we need - // to shift the content inside the popup by one pixel. - int gtk_offset = 0; - if (theme_provider_->UseGtkTheme()) - gtk_offset = kGtkHorizontalOffset; - + // TODO(deanm): Intersect the line and damage rects, and only repaint and + // layout the lines that are actually damaged. For now paint everything. for (size_t i = 0; i < result.size(); ++i) { gfx::Rect line_rect = GetRectForLine(i, window_rect.width()); // Only repaint and layout damaged lines. @@ -570,19 +439,18 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget, bool is_selected = (model_->selected_line() == i); bool is_hovered = (model_->hovered_line() == i); if (is_selected || is_hovered) { - gdk_gc_set_rgb_fg_color(gc, is_selected ? &selected_background_color_ : - &hovered_background_color_); + gdk_gc_set_rgb_fg_color(gc, is_selected ? &kSelectedBackgroundColor : + &kHoveredBackgroundColor); // This entry is selected or hovered, fill a rect with the color. gdk_draw_rectangle(drawable, gc, TRUE, line_rect.x(), line_rect.y(), line_rect.width(), line_rect.height()); } - int icon_start_x = ltr ? (kIconLeftPadding - gtk_offset) : - (line_rect.width() - kIconLeftPadding - kIconWidth + gtk_offset); + int icon_start_x = ltr ? kIconLeftPadding : + line_rect.width() - kIconLeftPadding - kIconWidth; // Draw the icon for this result. - DrawFullPixbuf(drawable, gc, - IconForMatch(theme_provider_, match, is_selected), + DrawFullPixbuf(drawable, gc, IconForMatch(match, is_selected), icon_start_x, line_rect.y() + kIconTopPadding); // Draw the results text vertically centered in the results space. @@ -596,11 +464,7 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget, // Note: We force to URL to LTR for all text directions. SetupLayoutForMatch(layout_, match.contents, match.contents_class, - is_selected ? &selected_content_text_color_ : - &content_text_color_, - is_selected ? &url_selected_text_color_ : - &url_text_color_, - std::string()); + &kContentTextColor, std::string()); int actual_content_width, actual_content_height; pango_layout_get_size(layout_, @@ -614,25 +478,22 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget, line_rect.y() + ((kHeightPerResult - actual_content_height) / 2)); gdk_draw_layout(drawable, gc, - ltr ? (kIconAreaWidth - gtk_offset) : - (text_width - actual_content_width + gtk_offset), + ltr ? kIconAreaWidth : text_width - actual_content_width, content_y, layout_); if (has_description) { pango_layout_set_width(layout_, (text_width - actual_content_width) * PANGO_SCALE); SetupLayoutForMatch(layout_, match.description, match.description_class, - is_selected ? &description_selected_text_color_ : - &description_text_color_, - is_selected ? &url_selected_text_color_ : - &url_text_color_, + is_selected ? &kDescriptionSelectedTextColor : + &kDescriptionTextColor, std::string(" - ")); gint actual_description_width; pango_layout_get_size(layout_, &actual_description_width, NULL); - gdk_draw_layout(drawable, gc, ltr ? - (kIconAreaWidth - gtk_offset + actual_content_width) : - (text_width - actual_content_width + gtk_offset - - (actual_description_width / PANGO_SCALE)), + gdk_draw_layout(drawable, gc, + ltr ? kIconAreaWidth + actual_content_width : + text_width - actual_content_width - + actual_description_width / PANGO_SCALE, content_y, layout_); } } @@ -641,3 +502,14 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget, return TRUE; } + +// static +AutocompletePopupView* AutocompletePopupView::CreatePopupView( + const gfx::Font& font, + AutocompleteEditView* edit_view, + AutocompleteEditModel* edit_model, + Profile* profile, + const BubblePositioner* bubble_positioner) { + return new AutocompletePopupViewGtk(edit_view, edit_model, profile, + bubble_positioner); +} diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h index 90cd2c9..f46cfb2 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h +++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,27 +10,23 @@ #include "base/basictypes.h" #include "base/scoped_ptr.h" #include "chrome/browser/autocomplete/autocomplete_popup_view.h" -#include "chrome/common/notification_observer.h" -#include "chrome/common/notification_registrar.h" #include "webkit/glue/window_open_disposition.h" class AutocompleteEditModel; class AutocompleteEditView; class AutocompletePopupModel; -class GtkThemeProvider; class Profile; class SkBitmap; -class AutocompletePopupViewGtk : public AutocompletePopupView, - public NotificationObserver { +class AutocompletePopupViewGtk : public AutocompletePopupView { public: AutocompletePopupViewGtk(AutocompleteEditView* edit_view, AutocompleteEditModel* edit_model, Profile* profile, - GtkWidget* location_bar); + const BubblePositioner* bubble_positioner); ~AutocompletePopupViewGtk(); - // Overridden from AutocompletePopupView: + // Implement the AutocompletePopupView interface. virtual bool IsOpen() const { return opened_; } virtual void InvalidateLine(size_t line); virtual void UpdatePopupAppearance(); @@ -38,11 +34,6 @@ class AutocompletePopupViewGtk : public AutocompletePopupView, virtual void OnDragCanceled() {} virtual AutocompletePopupModel* GetModel(); - // Overridden from NotificationObserver: - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - private: void Show(size_t num_results); void Hide(); @@ -88,7 +79,7 @@ class AutocompletePopupViewGtk : public AutocompletePopupView, scoped_ptr model_; AutocompleteEditView* edit_view_; - GtkWidget* location_bar_; + const BubblePositioner* bubble_positioner_; // Our popup window, which is the only widget used, and we paint it on our // own. This widget shouldn't be exposed outside of this class. @@ -96,22 +87,6 @@ class AutocompletePopupViewGtk : public AutocompletePopupView, // The pango layout object created from the window, cached across exposes. PangoLayout* layout_; - GtkThemeProvider* theme_provider_; - NotificationRegistrar registrar_; - - // A list of colors which we should use for drawing the popup. These change - // between gtk and normal mode. - GdkColor border_color_; - GdkColor background_color_; - GdkColor selected_background_color_; - GdkColor hovered_background_color_; - GdkColor content_text_color_; - GdkColor selected_content_text_color_; - GdkColor url_text_color_; - GdkColor url_selected_text_color_; - GdkColor description_text_color_; - GdkColor description_selected_text_color_; - // Whether our popup is currently open / shown, or closed / hidden. bool opened_; diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_mac.h b/chrome/browser/autocomplete/autocomplete_popup_view_mac.h index 56d20fd..a430f58 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_view_mac.h +++ b/chrome/browser/autocomplete/autocomplete_popup_view_mac.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -32,6 +32,7 @@ class AutocompletePopupViewMac : public AutocompletePopupView { public: AutocompletePopupViewMac(AutocompleteEditViewMac* edit_view, AutocompleteEditModel* edit_model, + const BubblePositioner* bubble_positioner, Profile* profile, NSTextField* field); virtual ~AutocompletePopupViewMac(); @@ -108,6 +109,7 @@ class AutocompletePopupViewMac : public AutocompletePopupView { scoped_ptr model_; AutocompleteEditViewMac* edit_view_; + const BubblePositioner* bubble_positioner_; // owned by toolbar controller NSTextField* field_; // owned by tab controller // Child window containing a matrix which implements the popup. diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm b/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm index 29ea9ab..644c065 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm +++ b/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,11 +10,11 @@ #include "chrome/browser/autocomplete/autocomplete_edit.h" #include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h" #include "chrome/browser/autocomplete/autocomplete_popup_model.h" +#include "chrome/browser/bubble_positioner.h" #include "chrome/browser/cocoa/event_utils.h" #include "gfx/rect.h" #include "grit/theme_resources.h" #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" -#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h" namespace { @@ -31,17 +31,17 @@ const int kCellHeightAdjust = 7.0; const CGFloat kPopupRoundingRadius = 3.5; // Gap between the field and the popup. -const CGFloat kPopupFieldGap = 0.0; +const CGFloat kPopupFieldGap = 2.0; // How opaque the popup window should be. This matches Windows (see // autocomplete_popup_contents_view.cc, kGlassPopupTransparency). const CGFloat kPopupAlpha = 240.0 / 255.0; // How much space to leave for the left and right margins. -const CGFloat kLeftRightMargin = 5.0; +const CGFloat kLeftRightMargin = 8.0; // How far to offset the text column from the left. -const CGFloat kTextXOffset = 29.0; +const CGFloat kTextXOffset = 33.0; // Animation duration when animating the popup window smaller. const CGFloat kShrinkAnimationDuration = 0.1; @@ -78,6 +78,54 @@ static const NSColor* DescriptionTextColor() { return [NSColor darkGrayColor]; } +// Helper to fetch and retain an image from the resource bundle. +NSImage* RetainedResourceImage(int resource_id) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + NSImage* image = rb.GetNSImageNamed(resource_id); + DCHECK(image); + return [image retain]; +} + +// Return the appropriate icon for the given match. Derived from the +// gtk code. +NSImage* MatchIcon(const AutocompleteMatch& match) { + if (match.starred) { + static NSImage* starImage = RetainedResourceImage(IDR_O2_STAR); + return starImage; + } + + switch (match.type) { + case AutocompleteMatch::URL_WHAT_YOU_TYPED: + case AutocompleteMatch::NAVSUGGEST: { + static NSImage* globeImage = RetainedResourceImage(IDR_O2_GLOBE); + return globeImage; + } + case AutocompleteMatch::HISTORY_URL: + case AutocompleteMatch::HISTORY_TITLE: + case AutocompleteMatch::HISTORY_BODY: + case AutocompleteMatch::HISTORY_KEYWORD: { + static NSImage* historyImage = RetainedResourceImage(IDR_O2_HISTORY); + return historyImage; + } + case AutocompleteMatch::SEARCH_WHAT_YOU_TYPED: + case AutocompleteMatch::SEARCH_HISTORY: + case AutocompleteMatch::SEARCH_SUGGEST: + case AutocompleteMatch::SEARCH_OTHER_ENGINE: { + static NSImage* searchImage = RetainedResourceImage(IDR_O2_SEARCH); + return searchImage; + } + case AutocompleteMatch::OPEN_HISTORY_PAGE: { + static NSImage* moreImage = RetainedResourceImage(IDR_O2_MORE); + return moreImage; + } + default: + NOTREACHED(); + break; + } + + return nil; +} + } // namespace // Helper for MatchText() to allow sharing code between the contents @@ -245,10 +293,12 @@ NSAttributedString* AutocompletePopupViewMac::MatchText( AutocompletePopupViewMac::AutocompletePopupViewMac( AutocompleteEditViewMac* edit_view, AutocompleteEditModel* edit_model, + const BubblePositioner* bubble_positioner, Profile* profile, NSTextField* field) : model_(new AutocompletePopupModel(this, edit_model, profile)), edit_view_(edit_view), + bubble_positioner_(bubble_positioner), field_(field), popup_(nil) { DCHECK(edit_view); @@ -315,12 +365,8 @@ void AutocompletePopupViewMac::UpdatePopupAppearance() { CreatePopupIfNeeded(); // Layout the popup and size it to land underneath the field. - // The field has a single-pixel border on the left and right. This - // needs to be factored out so that the popup window's border (which - // is outside the frame) lines up. - const int kLocationStackEdgeWidth = 1; - NSRect r = NSInsetRect([field_ convertRect:[field_ bounds] toView:nil], - kLocationStackEdgeWidth, 0); + NSRect r = + NSRectFromCGRect(bubble_positioner_->GetLocationStackBounds().ToCGRect()); r.origin = [[field_ window] convertBaseToScreen:r.origin]; DCHECK_GT(r.size.width, 0.0); @@ -340,9 +386,7 @@ void AutocompletePopupViewMac::UpdatePopupAppearance() { for (size_t ii = 0; ii < rows; ++ii) { AutocompleteButtonCell* cell = [matrix cellAtRow:ii column:0]; const AutocompleteMatch& match = model_->result().match_at(ii); - const int resource_id = match.starred ? IDR_OMNIBOX_STAR - : AutocompleteMatch::TypeToIcon(match.type); - [cell setImage:AutocompleteEditViewMac::ImageForResource(resource_id)]; + [cell setImage:MatchIcon(match)]; [cell setAttributedTitle:MatchText(match, resultFont, r.size.width)]; } @@ -463,11 +507,7 @@ void AutocompletePopupViewMac::OpenURLForRow(int row, bool force_background) { imageRect.origin.y += floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2); imageRect.origin.x += kLeftRightMargin; - [image setFlipped:[controlView isFlipped]]; - [image drawInRect:imageRect - fromRect:NSZeroRect // Entire image - operation:NSCompositeSourceOver - fraction:1.0]; + [self drawImage:image withFrame:imageRect inView:controlView]; } // Adjust the title position to be lined up under the field's text. @@ -664,15 +704,10 @@ void AutocompletePopupViewMac::OpenURLForRow(int row, bool force_background) { // This handles drawing the decorations of the rounded popup window, // calling on NSMatrix to draw the actual contents. - (void)drawRect:(NSRect)rect { - // Apparently this expects flipped coordinates, because in order to - // round the bottom corners visually, I need to specify the top - // corners here. NSBezierPath* path = - [NSBezierPath gtm_bezierPathWithRoundRect:[self bounds] - topLeftCornerRadius:kPopupRoundingRadius - topRightCornerRadius:kPopupRoundingRadius - bottomLeftCornerRadius:0.0 - bottomRightCornerRadius:0.0]; + [NSBezierPath bezierPathWithRoundedRect:[self bounds] + xRadius:kPopupRoundingRadius + yRadius:kPopupRoundingRadius]; // Draw the matrix clipped to our border. [NSGraphicsContext saveGraphicsState]; diff --git a/chrome/browser/autocomplete/history_contents_provider.cc b/chrome/browser/autocomplete/history_contents_provider.cc index 1e72ceb..ac81c31 100644 --- a/chrome/browser/autocomplete/history_contents_provider.cc +++ b/chrome/browser/autocomplete/history_contents_provider.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -207,9 +207,11 @@ AutocompleteMatch HistoryContentsProvider::ResultToMatch( // Also show star in popup. AutocompleteMatch match(this, score, false, MatchInTitle(result) ? AutocompleteMatch::HISTORY_TITLE : AutocompleteMatch::HISTORY_BODY); - match.fill_into_edit = StringForURLDisplay(result.url(), true, trim_http_); + match.fill_into_edit = StringForURLDisplay(result.url(), true); match.destination_url = result.url(); match.contents = match.fill_into_edit; + if (trim_http_) + TrimHttpPrefix(&match.contents); match.contents_class.push_back( ACMatchClassification(0, ACMatchClassification::URL)); match.description = result.title(); diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc index a748700..2708d47 100644 --- a/chrome/browser/autocomplete/history_url_provider.cc +++ b/chrome/browser/autocomplete/history_url_provider.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -256,14 +256,10 @@ AutocompleteMatch HistoryURLProvider::SuggestExactInput( const GURL& url = input.canonicalized_url(); if (url.is_valid()) { match.destination_url = url; - match.fill_into_edit = StringForURLDisplay(url, false, false); + match.fill_into_edit = StringForURLDisplay(url, false); // NOTE: Don't set match.input_location (to allow inline autocompletion) // here, it's surprising and annoying. // Trim off "http://" if the user didn't type it. - // Double NOTE: we use TrimHttpPrefix here rather than StringForURLDisplay - // to strip the http as we need to know the offset so we can adjust the - // match_location below. StringForURLDisplay and TrimHttpPrefix have - // slightly different behavior when stripping http as well. const size_t offset = trim_http ? TrimHttpPrefix(&match.fill_into_edit) : 0; // Try to highlight "innermost" match location. If we fix up "w" into @@ -832,13 +828,17 @@ AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch( DCHECK(match.destination_url.is_valid()); size_t inline_autocomplete_offset = history_match.input_location + params->input.text().length(); - const net::FormatUrlTypes format_types = - (params->trim_http && !history_match.match_in_scheme) ? - net::kFormatUrlOmitAll : net::kFormatUrlOmitUsernamePassword; match.fill_into_edit = net::FormatUrl(info.url(), - match_type == WHAT_YOU_TYPED ? std::wstring() : params->languages, - format_types, UnescapeRule::SPACES, NULL, NULL, - &inline_autocomplete_offset); + match_type == WHAT_YOU_TYPED ? std::wstring() : params->languages, true, + UnescapeRule::SPACES, NULL, NULL, &inline_autocomplete_offset); + size_t offset = 0; + if (params->trim_http && !history_match.match_in_scheme) { + offset = TrimHttpPrefix(&match.fill_into_edit); + if (inline_autocomplete_offset != std::wstring::npos) { + DCHECK(inline_autocomplete_offset >= offset); + inline_autocomplete_offset -= offset; + } + } if (!params->input.prevent_inline_autocomplete()) match.inline_autocomplete_offset = inline_autocomplete_offset; DCHECK((match.inline_autocomplete_offset == std::wstring::npos) || @@ -846,8 +846,15 @@ AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch( size_t match_start = history_match.input_location; match.contents = net::FormatUrl(info.url(), - match_type == WHAT_YOU_TYPED ? std::wstring() : params->languages, - format_types, UnescapeRule::SPACES, NULL, NULL, &match_start); + match_type == WHAT_YOU_TYPED ? std::wstring() : params->languages, true, + UnescapeRule::SPACES, NULL, NULL, &match_start); + if (offset) { + TrimHttpPrefix(&match.contents); + if (match_start != std::wstring::npos) { + DCHECK(match_start >= offset); + match_start -= offset; + } + } if ((match_start != std::wstring::npos) && (inline_autocomplete_offset != std::wstring::npos) && (inline_autocomplete_offset != match_start)) { diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc index acba81e..5833611 100644 --- a/chrome/browser/autocomplete/search_provider.cc +++ b/chrome/browser/autocomplete/search_provider.cc @@ -98,8 +98,8 @@ void SearchProvider::Start(const AutocompleteInput& input, // User typed "?" alone. Give them a placeholder result indicating what // this syntax does. if (default_provider) { - AutocompleteMatch match; - match.provider = this; + AutocompleteMatch match(this, 0, false, + AutocompleteMatch::SEARCH_WHAT_YOU_TYPED); match.contents.assign(l10n_util::GetString(IDS_EMPTY_KEYWORD_VALUE)); match.contents_class.push_back( ACMatchClassification(0, ACMatchClassification::NONE)); @@ -737,9 +737,10 @@ AutocompleteMatch SearchProvider::NavigationToMatch( AutocompleteMatch match(this, relevance, false, AutocompleteMatch::NAVSUGGEST); match.destination_url = navigation.url; - const bool trim_http = !url_util::FindAndCompareScheme( - WideToUTF8(input_text), chrome::kHttpScheme, NULL); - match.contents = StringForURLDisplay(navigation.url, true, trim_http); + match.contents = StringForURLDisplay(navigation.url, true); + if (!url_util::FindAndCompareScheme(WideToUTF8(input_text), + chrome::kHttpScheme, NULL)) + TrimHttpPrefix(&match.contents); AutocompleteMatch::ClassifyMatchInString(input_text, match.contents, ACMatchClassification::URL, &match.contents_class); diff --git a/chrome/browser/bookmarks/bookmark_table_model.cc b/chrome/browser/bookmarks/bookmark_table_model.cc index 0ac5416..f7848e4 100644 --- a/chrome/browser/bookmarks/bookmark_table_model.cc +++ b/chrome/browser/bookmarks/bookmark_table_model.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -325,8 +325,8 @@ std::wstring BookmarkTableModel::GetText(int row, int column_id) { std::wstring languages = model_ && model_->profile() ? model_->profile()->GetPrefs()->GetString(prefs::kAcceptLanguages) : std::wstring(); - std::wstring url_text = net::FormatUrl(node->GetURL(), languages, - net::kFormatUrlOmitAll, UnescapeRule::SPACES, NULL, NULL, NULL); + std::wstring url_text = net::FormatUrl(node->GetURL(), languages, false, + UnescapeRule::SPACES, NULL, NULL, NULL); if (base::i18n::IsRTL()) base::i18n::WrapStringWithLTRFormatting(&url_text); return url_text; diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc index 4ffeeb2..2214e4c 100644 --- a/chrome/browser/bookmarks/bookmark_utils.cc +++ b/chrome/browser/bookmarks/bookmark_utils.cc @@ -224,8 +224,7 @@ bool DoesBookmarkContainWords(const BookmarkNode* node, DoesBookmarkTextContainWords( l10n_util::ToLower(UTF8ToWide(node->GetURL().spec())), words) || DoesBookmarkTextContainWords(l10n_util::ToLower(net::FormatUrl( - node->GetURL(), languages, net::kFormatUrlOmitNothing, - UnescapeRule::NORMAL, NULL, NULL, NULL)), words); + node->GetURL(), languages, false, true, NULL, NULL, NULL)), words); } } // namespace diff --git a/chrome/browser/browser_theme_pack.cc b/chrome/browser/browser_theme_pack.cc index 130a6e8..d0252f1 100644 --- a/chrome/browser/browser_theme_pack.cc +++ b/chrome/browser/browser_theme_pack.cc @@ -4,26 +4,37 @@ #include "chrome/browser/browser_theme_pack.h" +#include +#include +#include +#include + #include "app/resource_bundle.h" #include "base/data_pack.h" +#include "base/logging.h" #include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "base/values.h" #include "chrome/browser/browser_theme_provider.h" #include "chrome/browser/chrome_thread.h" +#include "chrome/browser/theme_resources_util.h" +#include "chrome/common/extensions/extension.h" #include "gfx/codec/png_codec.h" #include "gfx/skbitmap_operations.h" #include "grit/app_resources.h" #include "grit/theme_resources.h" #include "net/base/file_stream.h" #include "net/base/net_errors.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkUnPreMultiply.h" namespace { // Version number of the current theme pack. We just throw out and rebuild // theme packs that aren't int-equal to this. -const int kThemePackVersion = 6; +const int kThemePackVersion = 7; // IDs that are in the DataPack won't clash with the positive integer // int32_t. kHeaderID should always have the maximum value because we want the @@ -120,33 +131,42 @@ PersistingImagesTable kPersistingImages[] = { { 21, IDR_FORWARD_H, NULL }, { 22, IDR_FORWARD_P, NULL }, { 23, IDR_RELOAD, NULL }, - { 24, IDR_RELOAD_NOBORDER, NULL }, - { 25, IDR_RELOAD_NOBORDER_CENTER, NULL }, - { 26, IDR_RELOAD_H, NULL }, - { 27, IDR_RELOAD_P, NULL }, - { 28, IDR_HOME, NULL }, - { 29, IDR_HOME_H, NULL }, - { 30, IDR_HOME_P, NULL }, - { 31, IDR_GO, NULL }, - { 32, IDR_GO_NOBORDER, NULL }, - { 33, IDR_GO_NOBORDER_CENTER, NULL }, - { 34, IDR_GO_H, NULL }, - { 35, IDR_GO_P, NULL }, - { 36, IDR_STOP, NULL }, - { 37, IDR_STOP_NOBORDER, NULL }, - { 38, IDR_STOP_NOBORDER_CENTER, NULL }, - { 39, IDR_STOP_H, NULL }, - { 40, IDR_STOP_P, NULL }, - { 41, IDR_MENU_BOOKMARK, NULL }, - { 42, IDR_MENU_PAGE, NULL }, - { 43, IDR_MENU_PAGE_RTL, NULL }, - { 44, IDR_MENU_CHROME, NULL }, - { 45, IDR_MENU_CHROME_RTL, NULL }, - { 46, IDR_MENU_DROPARROW, NULL }, - { 47, IDR_THROBBER, NULL }, - { 48, IDR_THROBBER_WAITING, NULL }, - { 49, IDR_THROBBER_LIGHT, NULL }, - { 50, IDR_LOCATIONBG, NULL } + { 24, IDR_RELOAD_H, NULL }, + { 25, IDR_RELOAD_P, NULL }, + { 26, IDR_HOME, NULL }, + { 27, IDR_HOME_H, NULL }, + { 28, IDR_HOME_P, NULL }, + { 29, IDR_STAR, NULL }, + { 30, IDR_STAR_NOBORDER, NULL }, + { 31, IDR_STAR_NOBORDER_CENTER, NULL }, + { 32, IDR_STAR_D, NULL }, + { 33, IDR_STAR_H, NULL }, + { 34, IDR_STAR_P, NULL }, + { 35, IDR_STARRED, NULL }, + { 36, IDR_STARRED_NOBORDER, NULL }, + { 37, IDR_STARRED_NOBORDER_CENTER, NULL }, + { 38, IDR_STARRED_H, NULL }, + { 39, IDR_STARRED_P, NULL }, + { 40, IDR_GO, NULL }, + { 41, IDR_GO_NOBORDER, NULL }, + { 42, IDR_GO_NOBORDER_CENTER, NULL }, + { 43, IDR_GO_H, NULL }, + { 44, IDR_GO_P, NULL }, + { 45, IDR_STOP, NULL }, + { 46, IDR_STOP_NOBORDER, NULL }, + { 47, IDR_STOP_NOBORDER_CENTER, NULL }, + { 48, IDR_STOP_H, NULL }, + { 49, IDR_STOP_P, NULL }, + { 50, IDR_MENU_BOOKMARK, NULL }, + { 51, IDR_MENU_PAGE, NULL }, + { 52, IDR_MENU_PAGE_RTL, NULL }, + { 53, IDR_MENU_CHROME, NULL }, + { 54, IDR_MENU_CHROME_RTL, NULL }, + { 55, IDR_MENU_DROPARROW, NULL }, + { 56, IDR_THROBBER, NULL }, + { 57, IDR_THROBBER_WAITING, NULL }, + { 58, IDR_THROBBER_LIGHT, NULL }, + { 59, IDR_LOCATIONBG, NULL } }; int GetPersistentIDByName(const std::string& key) { @@ -496,8 +516,6 @@ bool BrowserThemePack::GetDisplayProperty(int id, int* result) const { SkBitmap* BrowserThemePack::GetBitmapNamed(int idr_id) const { int prs_id = GetPersistentIDByIDR(idr_id); - if (prs_id == -1) - return NULL; // Check our cache of prepared images, first. ImageCache::const_iterator image_iter = prepared_images_.find(prs_id); @@ -947,7 +965,6 @@ void BrowserThemePack::GenerateTintedButtons( for (std::set::const_iterator it = idr_ids.begin(); it != idr_ids.end(); ++it) { int prs_id = GetPersistentIDByIDR(*it); - DCHECK(prs_id > 0); // Fetch the image by IDR... scoped_ptr button(new SkBitmap(*rb.GetBitmapNamed(*it))); diff --git a/chrome/browser/browser_theme_provider.cc b/chrome/browser/browser_theme_provider.cc index 92fefc3..d682548 100644 --- a/chrome/browser/browser_theme_provider.cc +++ b/chrome/browser/browser_theme_provider.cc @@ -1,21 +1,40 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/browser_theme_provider.h" #include "app/resource_bundle.h" -#include "base/utf_string_conversions.h" +#include "base/file_util.h" +#include "base/stl_util-inl.h" +#include "base/string_util.h" +#include "base/thread.h" +#include "base/values.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_theme_pack.h" +#include "chrome/browser/browser_window.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" +#include "chrome/browser/theme_resources_util.h" #include "chrome/common/chrome_constants.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/notification_details.h" #include "chrome/common/notification_service.h" +#include "chrome/common/notification_source.h" #include "chrome/common/notification_type.h" #include "chrome/common/pref_names.h" +#include "gfx/codec/png_codec.h" +#include "gfx/skbitmap_operations.h" #include "grit/app_resources.h" #include "grit/theme_resources.h" +#include "net/base/file_stream.h" +#include "net/base/net_errors.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkUnPreMultiply.h" #if defined(OS_WIN) #include "app/win_util.h" @@ -43,15 +62,15 @@ SkColor TintForUnderline(SkColor input) { } // Default colors. -const SkColor kDefaultColorFrame = SkColorSetRGB(66, 116, 201); -const SkColor kDefaultColorFrameInactive = SkColorSetRGB(161, 182, 228); +const SkColor kDefaultColorFrame = SkColorSetRGB(77, 139, 217); +const SkColor kDefaultColorFrameInactive = SkColorSetRGB(152, 188, 233); const SkColor kDefaultColorFrameIncognito = SkColorSetRGB(83, 106, 139); const SkColor kDefaultColorFrameIncognitoInactive = SkColorSetRGB(126, 139, 156); #if defined(OS_MACOSX) const SkColor kDefaultColorToolbar = SkColorSetRGB(230, 230, 230); #else -const SkColor kDefaultColorToolbar = SkColorSetRGB(223, 223, 223); +const SkColor kDefaultColorToolbar = SkColorSetRGB(210, 225, 246); #endif const SkColor kDefaultColorTabText = SK_ColorBLACK; #if defined(OS_MACOSX) @@ -135,16 +154,15 @@ bool HasThemeableImage(int themeable_image_id) { } // The image resources that will be tinted by the 'button' tint value. -// If you change this list, you must increment the version number in -// browser_theme_pack.cc and you should assign persistant ids to the -// data table at the start of said file or otherwise tinted versions of -// these resources will not be created. const int kToolbarButtonIDs[] = { IDR_BACK, IDR_BACK_D, IDR_BACK_H, IDR_BACK_P, IDR_FORWARD, IDR_FORWARD_D, IDR_FORWARD_H, IDR_FORWARD_P, - IDR_RELOAD, IDR_RELOAD_NOBORDER, IDR_RELOAD_NOBORDER_CENTER, IDR_RELOAD_H, - IDR_RELOAD_P, + IDR_RELOAD, IDR_RELOAD_H, IDR_RELOAD_P, IDR_HOME, IDR_HOME_H, IDR_HOME_P, + IDR_STAR, IDR_STAR_NOBORDER, IDR_STAR_NOBORDER_CENTER, IDR_STAR_D, IDR_STAR_H, + IDR_STAR_P, + IDR_STARRED, IDR_STARRED_NOBORDER, IDR_STARRED_NOBORDER_CENTER, IDR_STARRED_H, + IDR_STARRED_P, IDR_GO, IDR_GO_NOBORDER, IDR_GO_NOBORDER_CENTER, IDR_GO_H, IDR_GO_P, IDR_STOP, IDR_STOP_NOBORDER, IDR_STOP_NOBORDER_CENTER, IDR_STOP_H, IDR_STOP_P, IDR_MENU_BOOKMARK, diff --git a/chrome/browser/bubble_positioner.h b/chrome/browser/bubble_positioner.h new file mode 100644 index 0000000..7ea4df0 --- /dev/null +++ b/chrome/browser/bubble_positioner.h @@ -0,0 +1,24 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_BUBBLE_POSITIONER_H_ +#define CHROME_BROWSER_BUBBLE_POSITIONER_H_ + +namespace gfx { +class Rect; +} + +// An object in the browser UI can implement this interface to provide display +// bounds for the omnibox bubble and info bubble views. +class BubblePositioner { + public: + // Returns the bounds of the "location bar" stack (including star/go buttons + // where relevant). The omnibox dropdown uses this to calculate its width and + // y-coordinate, and views showing InfoBubbles use it to find the y-coordinate + // they should show at, so that all "bubble" UIs show up at the same vertical + // position. + virtual gfx::Rect GetLocationStackBounds() const = 0; +}; + +#endif // CHROME_BROWSER_BUBBLE_POSITIONER_H_ diff --git a/chrome/browser/cert_store.cc b/chrome/browser/cert_store.cc index 89c5ffe..4d804ca 100644 --- a/chrome/browser/cert_store.cc +++ b/chrome/browser/cert_store.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -88,8 +88,7 @@ bool CertStore::RetrieveCert(int cert_id, CertMap::iterator iter = id_to_cert_.find(cert_id); if (iter == id_to_cert_.end()) return false; - if (cert) - *cert = iter->second; + *cert = iter->second; return true; } diff --git a/chrome/browser/cert_store.h b/chrome/browser/cert_store.h index 0b19540..995a3db 100644 --- a/chrome/browser/cert_store.h +++ b/chrome/browser/cert_store.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -34,9 +34,9 @@ class CertStore : public NotificationObserver { // Note: ids starts at 1. int StoreCert(net::X509Certificate* cert, int render_process_host_id); - // Tries to retrieve the previously stored cert associated with the specified - // |cert_id|. Returns whether the cert could be found, and, if |cert| is - // non-NULL, copies it in. + // Retrieves the previously stored cert associated with the specified + // |cert_id| and set it in |cert|. Returns false if no cert was found for + // that id. bool RetrieveCert(int cert_id, scoped_refptr* cert); // NotificationObserver implementation. diff --git a/chrome/browser/chromeos/compact_location_bar_host.cc b/chrome/browser/chromeos/compact_location_bar_host.cc index eaba6ef..a412cb6 100644 --- a/chrome/browser/chromeos/compact_location_bar_host.cc +++ b/chrome/browser/chromeos/compact_location_bar_host.cc @@ -22,6 +22,7 @@ #include "chrome/browser/views/frame/browser_view.h" #include "chrome/browser/views/tabs/tab.h" #include "chrome/browser/views/tabs/tab_strip.h" +#include "chrome/browser/views/toolbar_star_toggle.h" #include "views/controls/scrollbar/native_scroll_bar.h" #include "views/focus/external_focus_tracker.h" #include "views/focus/view_storage.h" @@ -267,6 +268,10 @@ void CompactLocationBarHost::SetEnabled(bool enabled) { } } +ToolbarStarToggle* CompactLocationBarHost::GetStarButton() { + return GetClbView()->star_button(); +} + void CompactLocationBarHost::Show(bool a) { MessageLoopForUI::current()->AddObserver(mouse_observer_.get()); DropdownBarHost::Show(a); diff --git a/chrome/browser/chromeos/compact_location_bar_host.h b/chrome/browser/chromeos/compact_location_bar_host.h index 7ec6a25..e6816fc 100644 --- a/chrome/browser/chromeos/compact_location_bar_host.h +++ b/chrome/browser/chromeos/compact_location_bar_host.h @@ -16,6 +16,7 @@ class BrowserView; class TabContents; class Tab; +class ToolbarStarToggle; namespace chromeos { @@ -60,6 +61,9 @@ class CompactLocationBarHost : public DropdownBarHost, // Enable/disable the compact location bar. void SetEnabled(bool enabled); + // Returns the star button for compact location bar. + ToolbarStarToggle* GetStarButton(); + // Overridden from DropdownBarhost. virtual void Show(bool animate); virtual void Hide(bool animate); diff --git a/chrome/browser/chromeos/compact_location_bar_view.cc b/chrome/browser/chromeos/compact_location_bar_view.cc index 9f7c066..af803e4 100644 --- a/chrome/browser/chromeos/compact_location_bar_view.cc +++ b/chrome/browser/chromeos/compact_location_bar_view.cc @@ -8,8 +8,10 @@ #include #include "app/l10n_util.h" +#include "app/drag_drop_types.h" #include "app/resource_bundle.h" #include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/bookmarks/bookmark_drag_data.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" #include "chrome/browser/browser_list.h" @@ -22,6 +24,7 @@ #include "chrome/browser/views/browser_actions_container.h" #include "chrome/browser/views/event_utils.h" #include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/toolbar_star_toggle.h" #include "gfx/canvas.h" #include "gfx/point.h" #include "grit/chromium_strings.h" @@ -30,10 +33,12 @@ #include "views/background.h" #include "views/controls/button/image_button.h" #include "views/controls/native/native_view_host.h" +#include "views/drag_utils.h" #include "views/widget/widget.h" #include "views/window/window.h" namespace chromeos { +const int kAutocompletePopupWidth = 700; const int kDefaultLocationEntryWidth = 250; const int kCompactLocationLeftMargin = 5; const int kCompactLocationRightMargin = 10; @@ -46,7 +51,8 @@ const int kWidgetsSeparatorWidth = 2; CompactLocationBarView::CompactLocationBarView(CompactLocationBarHost* host) : DropdownBarView(host), reload_(NULL), - browser_actions_(NULL) { + browser_actions_(NULL), + star_(NULL) { SetFocusable(true); } @@ -95,7 +101,7 @@ void CompactLocationBarView::Init() { reload_->SetImage(views::CustomButton::BS_PUSHED, tp->GetBitmapNamed(IDR_RELOAD_P)); reload_->SetBackground(color, background, - tp->GetBitmapNamed(IDR_RELOAD_MASK)); + tp->GetBitmapNamed(IDR_BUTTON_MASK)); AddChildView(reload_); @@ -114,6 +120,14 @@ void CompactLocationBarView::Init() { location_entry_view_->set_focus_view(this); location_entry_view_->Attach(location_entry_->GetNativeView()); + star_ = new ToolbarStarToggle(this); + star_->SetDragController(this); + star_->set_profile(browser()->profile()); + star_->set_host_view(this); + star_->set_bubble_positioner(this); + star_->Init(); + AddChildView(star_); + location_entry_->Update(browser()->GetSelectedTabContents()); // Note: we tell the BrowserActionsContainer not to save its size because @@ -131,12 +145,15 @@ gfx::Size CompactLocationBarView::GetPreferredSize() { return gfx::Size(); // Not initialized yet, do nothing. gfx::Size reload_size = reload_->GetPreferredSize(); + gfx::Size star_size = star_->GetPreferredSize(); gfx::Size location_size = location_entry_view_->GetPreferredSize(); gfx::Size ba_size = browser_actions_->GetPreferredSize(); - int width = kCompactLocationLeftMargin + reload_size.width() + + int width = + reload_size.width() + kEntryLeftMargin + star_size.width() + std::max(kDefaultLocationEntryWidth, location_entry_view_->GetPreferredSize().width()) + ba_size.width() + + kCompactLocationLeftMargin + kCompactLocationRightMargin; return gfx::Size(width, kDefaultLocationBarHeight); } @@ -151,7 +168,12 @@ void CompactLocationBarView::Layout() { int reload_y = (height() - reload_size.height()) / 2; reload_->SetBounds(cur_x, reload_y, reload_size.width(), reload_size.height()); - cur_x += reload_size.width(); + cur_x += reload_size.width() + kEntryLeftMargin; + + gfx::Size star_size = star_->GetPreferredSize(); + int star_y = (height() - star_size.height()) / 2; + star_->SetBounds(cur_x, star_y, star_size.width(), star_size.height()); + cur_x += star_size.width(); gfx::Size ba_size = browser_actions_->GetPreferredSize(); int ba_y = (height() - ba_size.height()) / 2; @@ -245,4 +267,62 @@ std::wstring CompactLocationBarView::GetTitle() const { return std::wstring(); } +//////////////////////////////////////////////////////////////////////////////// +// BubblePositioner overrides: +gfx::Rect CompactLocationBarView::GetLocationStackBounds() const { + gfx::Point lower_left(0, height()); + ConvertPointToScreen(this, &lower_left); + gfx::Rect popup = gfx::Rect(lower_left.x(), lower_left.y(), + kAutocompletePopupWidth, 0); + return popup.AdjustToFit(GetWidget()->GetWindow()->GetBounds()); +} + +//////////////////////////////////////////////////////////////////////////////// +// views::DragController overrides: +void CompactLocationBarView::WriteDragData(views::View* sender, + const gfx::Point& press_pt, + OSExchangeData* data) { + DCHECK(GetDragOperations(sender, press_pt) != DragDropTypes::DRAG_NONE); + + UserMetrics::RecordAction(UserMetricsAction("CompactLocationBar_DragStar"), + browser()->profile()); + + // If there is a bookmark for the URL, add the bookmark drag data for it. We + // do this to ensure the bookmark is moved, rather than creating an new + // bookmark. + TabContents* tab = browser()->GetSelectedTabContents(); + if (tab) { + Profile* profile = browser()->profile(); + if (profile && profile->GetBookmarkModel()) { + const BookmarkNode* node = profile->GetBookmarkModel()-> + GetMostRecentlyAddedNodeForURL(tab->GetURL()); + if (node) { + BookmarkDragData bookmark_data(node); + bookmark_data.Write(profile, data); + } + } + + drag_utils::SetURLAndDragImage(tab->GetURL(), + UTF16ToWideHack(tab->GetTitle()), + tab->GetFavIcon(), + data); + } +} + +int CompactLocationBarView::GetDragOperations(views::View* sender, + const gfx::Point& p) { + DCHECK(sender == star_); + TabContents* tab = browser()->GetSelectedTabContents(); + if (!tab || !tab->ShouldDisplayURL() || !tab->GetURL().is_valid()) { + return DragDropTypes::DRAG_NONE; + } + Profile* profile = browser()->profile(); + if (profile && profile->GetBookmarkModel() && + profile->GetBookmarkModel()->IsBookmarked(tab->GetURL())) { + return DragDropTypes::DRAG_MOVE | DragDropTypes::DRAG_COPY | + DragDropTypes::DRAG_LINK; + } + return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK; +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/compact_location_bar_view.h b/chrome/browser/chromeos/compact_location_bar_view.h index ec284b0..e4f8d73 100644 --- a/chrome/browser/chromeos/compact_location_bar_view.h +++ b/chrome/browser/chromeos/compact_location_bar_view.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_CHROMEOS_COMPACT_LOCATION_BAR_VIEW_H_ #include "base/basictypes.h" +#include "chrome/browser/bubble_positioner.h" #include "chrome/browser/autocomplete/autocomplete_edit.h" #include "chrome/browser/chromeos/compact_location_bar_host.h" #include "chrome/browser/views/dropdown_bar_view.h" @@ -16,9 +17,11 @@ class AutocompleteEditViewGtk; class Browser; class BrowserActionsContainer; class BrowserView; +class ToolbarStarToggleGtk; class Tab; class TabContents; class TabStrip; +class ToolbarStarToggle; namespace views { class ImageButton; @@ -32,7 +35,9 @@ namespace chromeos { // navigation bar mode. class CompactLocationBarView : public DropdownBarView, public views::ButtonListener, - public AutocompleteEditController { + public AutocompleteEditController, + public BubblePositioner, + public views::DragController { public: explicit CompactLocationBarView(CompactLocationBarHost* host); ~CompactLocationBarView(); @@ -42,6 +47,8 @@ class CompactLocationBarView : public DropdownBarView, void Update(const TabContents* contents); + ToolbarStarToggle* star_button() const { return star_; } + private: Browser* browser() const; @@ -74,6 +81,20 @@ class CompactLocationBarView : public DropdownBarView, virtual SkBitmap GetFavIcon() const; virtual std::wstring GetTitle() const; + // BubblePositioner implementation. + virtual gfx::Rect GetLocationStackBounds() const; + + // views::DragController implementation. + virtual void WriteDragData(View* sender, + const gfx::Point& press_pt, + OSExchangeData* data); + virtual int GetDragOperations(View* sender, const gfx::Point& p); + virtual bool CanStartDrag(View* sender, + const gfx::Point& press_pt, + const gfx::Point& p) { + return true; + } + CompactLocationBarHost* clb_host() { return static_cast(host()); } @@ -82,6 +103,7 @@ class CompactLocationBarView : public DropdownBarView, scoped_ptr location_entry_; views::NativeViewHost* location_entry_view_; BrowserActionsContainer* browser_actions_; + ToolbarStarToggle* star_; DISALLOW_COPY_AND_ASSIGN(CompactLocationBarView); }; diff --git a/chrome/browser/chromeos/frame/browser_view.cc b/chrome/browser/chromeos/frame/browser_view.cc index eb2029c..254be1d 100644 --- a/chrome/browser/chromeos/frame/browser_view.cc +++ b/chrome/browser/chromeos/frame/browser_view.cc @@ -28,6 +28,7 @@ #include "chrome/browser/views/tabs/tab.h" #include "chrome/browser/views/tabs/tab_strip.h" #include "chrome/browser/views/toolbar_view.h" +#include "chrome/browser/views/toolbar_star_toggle.h" #include "gfx/canvas.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" @@ -440,6 +441,19 @@ void BrowserView::ChildPreferredSizeChanged(View* child) { SchedulePaint(); } +void BrowserView::SetStarredState(bool is_starred) { + ::BrowserView::SetStarredState(is_starred); + compact_location_bar_host_->GetStarButton()->SetToggled(is_starred); +} + +void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) { + if (is_compact_style()) + compact_location_bar_host_->GetStarButton()->ShowStarBubble( + url, !already_bookmarked); + else + ::BrowserView::ShowBookmarkBubble(url, already_bookmarked); +} + // views::ButtonListener overrides. void BrowserView::ButtonPressed(views::Button* sender, const views::Event& event) { @@ -450,7 +464,7 @@ void BrowserView::ButtonPressed(views::Button* sender, origin.Offset(kAppLauncherLeftPadding, 0); views::RootView::ConvertPointToScreen(this, &origin); bounds.set_origin(origin); - ::AppLauncher::Show(browser(), bounds, gfx::Point()); + ::AppLauncher::Show(browser(), bounds); } // views::ContextMenuController overrides. diff --git a/chrome/browser/chromeos/frame/browser_view.h b/chrome/browser/chromeos/frame/browser_view.h index cd868c7..0d3dd2a 100644 --- a/chrome/browser/chromeos/frame/browser_view.h +++ b/chrome/browser/chromeos/frame/browser_view.h @@ -66,6 +66,8 @@ class BrowserView : public ::BrowserView, virtual views::LayoutManager* CreateLayoutManager() const; virtual BaseTabStrip* CreateTabStrip(TabStripModel* tab_strip_model); virtual void ChildPreferredSizeChanged(View* child); + virtual void SetStarredState(bool is_starred); + virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked); // views::ButtonListener overrides. virtual void ButtonPressed(views::Button* sender, const views::Event& event); diff --git a/chrome/browser/cocoa/autocomplete_text_field.h b/chrome/browser/cocoa/autocomplete_text_field.h index 8e16705..1b1856d 100644 --- a/chrome/browser/cocoa/autocomplete_text_field.h +++ b/chrome/browser/cocoa/autocomplete_text_field.h @@ -119,13 +119,6 @@ class AutocompleteTextFieldObserver { // is not over an action. - (NSMenu*)actionMenuForEvent:(NSEvent*)event; -// Return the rectangle the star is being shown in, for purposes of -// positioning the bookmark bubble. -- (NSRect)starIconFrame; - -// If the location icon is draggable, return its drag pasteboard. -- (NSPasteboard*)locationDragPasteboard; - @end #endif // CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_ diff --git a/chrome/browser/cocoa/autocomplete_text_field.mm b/chrome/browser/cocoa/autocomplete_text_field.mm index a07cac1..60d3507 100644 --- a/chrome/browser/cocoa/autocomplete_text_field.mm +++ b/chrome/browser/cocoa/autocomplete_text_field.mm @@ -124,10 +124,14 @@ return; } - // Give the cell a chance to intercept clicks in page-actions and - // other decorative items. - if ([cell mouseDown:theEvent inRect:bounds ofView:self]) { - return; + // If the user clicked on one of the icons (security icon, Page + // Actions, etc), let the icon handle the click. + for (AutocompleteTextFieldIcon* icon in [cell layedOutIcons:bounds]) { + const NSRect iconRect = [icon rect]; + if (NSMouseInRect(location, iconRect, flipped)) { + [icon view]->OnMousePressed(iconRect); + return; + } } NSText* editor = [self currentEditor]; @@ -195,7 +199,6 @@ // Show the I-beam cursor unless the mouse is over an image within the field // (Page Actions or the security icon) in which case show the arrow cursor. -// TODO(rohitrao): Should default to the arrow cursor. http://crbug.com/41612 - (void)resetCursorRects { NSRect fieldBounds = [self bounds]; [self addCursorRect:fieldBounds cursor:[NSCursor IBeamCursor]]; @@ -203,17 +206,8 @@ AutocompleteTextFieldCell* cell = [self autocompleteTextFieldCell]; for (AutocompleteTextFieldIcon* icon in [cell layedOutIcons:fieldBounds]) [self addCursorRect:[icon rect] cursor:[NSCursor arrowCursor]]; - - // Special-case the location image, since it is not in |-layedOutIcons|. - const NSRect locationIconFrame = [cell locationIconFrameForFrame:fieldBounds]; - [self addCursorRect:locationIconFrame cursor:[NSCursor arrowCursor]]; } -// TODO(shess): -resetFieldEditorFrameIfNeeded is the place where -// changes to the cell layout should be flushed. LocationBarViewMac -// and ToolbarController are calling this routine directly, and I -// think they are probably wrong. -// http://crbug.com/40053 - (void)updateCursorAndToolTipRects { // This will force |resetCursorRects| to be called, as it is not to be called // directly. @@ -377,13 +371,4 @@ actionMenuForEvent:event inRect:[self bounds] ofView:self]; } -- (NSRect)starIconFrame { - AutocompleteTextFieldCell* cell = [self autocompleteTextFieldCell]; - return [cell starIconFrameForFrame:[self bounds]]; -} - -- (NSPasteboard*)locationDragPasteboard { - return [[self autocompleteTextFieldCell] locationDragPasteboard]; -} - @end diff --git a/chrome/browser/cocoa/autocomplete_text_field_cell.h b/chrome/browser/cocoa/autocomplete_text_field_cell.h index bc791cf..1e0a3c5 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_cell.h +++ b/chrome/browser/cocoa/autocomplete_text_field_cell.h @@ -13,15 +13,7 @@ class ExtensionAction; // Holds a |LocationBarImageView| and its current rect. Do not keep references // to this object, only use it directly after calling |-layedOutIcons:|. -// TODO(shess): This class is basically a helper for laying out the -// icons. Try to refactor it away. If that is not reasonable, at -// least split the image and label cases into subclasses once the -// Omnibox stuff is settled. @interface AutocompleteTextFieldIcon : NSObject { - // YES to draw the label part of |view_|, otherwise draw the image - // part. - BOOL isLabel_; - // The frame rect of |view_|. NSRect rect_; @@ -29,20 +21,12 @@ class ExtensionAction; LocationBarViewMac::LocationBarImageView* view_; } +// Returns a new AutocompleteTextFieldIcon object. ++ (AutocompleteTextFieldIcon*) + iconWithRect:(NSRect)rect + view:(LocationBarViewMac::LocationBarImageView*)view; @property(assign, nonatomic) NSRect rect; @property(assign, nonatomic) LocationBarViewMac::LocationBarImageView* view; - -- (id)initImageWithView:(LocationBarViewMac::LocationBarImageView*)view; -- (id)initLabelWithView:(LocationBarViewMac::LocationBarImageView*)view; - -// Position |view_| right-justified in |frame|. -- (void)positionInFrame:(NSRect)frame; - -// Draw image or label of |view_| in |rect_| within |controlView|. -// Only call after |-positionInFrame:| has set |rect_| (or after an -// explicit |-setRect:|). -- (void)drawInView:(NSView*)controlView; - @end // AutocompleteTextFieldCell extends StyledTextFieldCell to provide support for @@ -60,17 +44,10 @@ class ExtensionAction; // side of the field. Exclusive WRT |keywordString_|; scoped_nsobject hintString_; - // The location icon sits at the left-hand side of the field. - // |keywordString_| overrides. - LocationBarViewMac::LocationIconView* locationIconView_; - - // The star icon sits at the right-hand side of the field when an - // URL is being shown. - LocationBarViewMac::LocationBarImageView* starIconView_; - - // The security label floats to the left of page actions at the - // right-hand side. - LocationBarViewMac::LocationBarImageView* securityLabelView_; + // View showing the state of the SSL connection. Owned by the location bar. + // Display is exclusive WRT the |hintString_| and |keywordString_|. + // This may be NULL during testing. + LocationBarViewMac::SecurityImageView* security_image_view_; // List of views showing visible Page Actions. Owned by the location bar. // Display is exclusive WRT the |hintString_| and |keywordString_|. @@ -100,58 +77,34 @@ class ExtensionAction; availableWidth:(CGFloat)width; - (void)clearKeywordAndHint; -- (void)setLocationIconView:(LocationBarViewMac::LocationIconView*)view; -- (void)setStarIconView:(LocationBarViewMac::LocationBarImageView*)view; -- (void)setSecurityLabelView:(LocationBarViewMac::LocationBarImageView*)view; +- (void)setSecurityImageView:(LocationBarViewMac::SecurityImageView*)view; - (void)setPageActionViewList:(LocationBarViewMac::PageActionViewList*)list; - (void)setContentSettingViewsList: (LocationBarViewMac::ContentSettingViews*)views; -// Returns the portion of the cell to use for displaying the location -// icon. -- (NSRect)locationIconFrameForFrame:(NSRect)cellFrame; - // Returns an array of the visible AutocompleteTextFieldIcon objects. Returns // only visible icons. - (NSArray*)layedOutIcons:(NSRect)cellFrame; -// Return the rectangle the star is being shown in, for purposes of -// positioning the bookmark bubble. -- (NSRect)starIconFrameForFrame:(NSRect)cellFrame; - -// Returns the portion of the cell to use for displaying the Page -// Action icon at the given index. May be NSZeroRect if the index's -// action is not visible. This does a linear walk over all page -// actions, so do not call this in a loop to get the position of all -// page actions. Use |-layedOutIcons:| instead in that case. -- (NSRect)pageActionFrameForIndex:(size_t)index inFrame:(NSRect)cellFrame; // Similar to |pageActionFrameForIndex:inFrame| but accepts an // ExtensionAction for when the index is not known. - (NSRect)pageActionFrameForExtensionAction:(ExtensionAction*)action inFrame:(NSRect)cellFrame; -// Find the icon under the event. |nil| if |theEvent| is not over -// anything. -- (AutocompleteTextFieldIcon*)iconForEvent:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView; +// Returns the portion of the cell to use for displaying the Page Action icon +// at the given index. May be NSZeroRect if the index's action is not visible. +// This does a linear walk over all page actions, so do not call this in a loop +// to get the position of all page actions. Use |-layedOutIcons:| instead in that +// case. +- (NSRect)pageActionFrameForIndex:(size_t)index inFrame:(NSRect)cellFrame; // Return the appropriate menu for any page actions under event. // Returns nil if no menu is present for the action, or if the event // is not over an action. -- (NSMenu*)actionMenuForEvent:(NSEvent*)theEvent +- (NSMenu*)actionMenuForEvent:(NSEvent*)event inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView; - -// Called by |AutocompleteTextField| to let page actions intercept -// clicks. Returns |YES| if the click has been intercepted. -- (BOOL)mouseDown:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView; - -// If the location icon is draggable, return its drag pasteboard. -- (NSPasteboard*)locationDragPasteboard; + ofView:(NSView*)aView; @end @@ -165,4 +118,8 @@ class ExtensionAction; // Returns the total number of installed Page Actions, visible or not. - (size_t)pageActionCount; +// Returns the portion of the cell to use for displaying the security (SSL lock) +// icon, leaving space for its label if any. +- (NSRect)securityImageFrameForFrame:(NSRect)cellFrame; + @end diff --git a/chrome/browser/cocoa/autocomplete_text_field_cell.mm b/chrome/browser/cocoa/autocomplete_text_field_cell.mm index 9801892..7b7f35c 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_cell.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_cell.mm @@ -7,20 +7,6 @@ #include "app/resource_bundle.h" #include "base/logging.h" #include "gfx/font.h" -#include "grit/theme_resources.h" - -@interface AutocompleteTextAttachmentCell : NSTextAttachmentCell { -} - -// TODO(shess): -// Override -cellBaselineOffset to allow the image to be shifted up or -// down relative to the containing text's baseline. - -// Draw the image using |DrawImageInRect()| helper function for -// |-setFlipped:| consistency with other image drawing. -- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView; - -@end namespace { @@ -49,28 +35,16 @@ const NSInteger kKeywordYInset = 4; // technique would be nice to have, though. const NSInteger kKeywordHintImageBaseline = -6; -// Drops the magnifying glass icon so that it looks centered in the -// keyword-search bubble. -const NSInteger kKeywordSearchImageBaseline = -5; - // The amount of padding on either side reserved for drawing an icon. const NSInteger kIconHorizontalPad = 3; // How far to shift bounding box of hint icon label down from top of field. -const NSInteger kIconLabelYOffset = 7; +const NSInteger kIconLabelYOffset = 5; // How far the editor insets itself, for purposes of determining if // decorations need to be trimmed. const CGFloat kEditorHorizontalInset = 3.0; -// Cause the location icon to line up above the icons in the popup. -const CGFloat kLocationIconXOffset = 6.0; -const CGFloat kLocationIconXPad = 1.0; - -// How long to wait for mouse-up on the location icon before assuming -// that the user wants to drag. -const NSTimeInterval kLocationIconDragTimeout = 0.25; - // Conveniences to centralize width+offset calculations. CGFloat WidthForHint(NSAttributedString* hintString) { return kHintXOffset + ceil([hintString size].width); @@ -80,103 +54,20 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { 2 * kKeywordTokenInset; } -// Convenience to draw |image| in the |rect| portion of |view|. -void DrawImageInRect(NSImage* image, NSView* view, const NSRect& rect) { - // If there is an image, make sure we calculated the target size - // correctly. - DCHECK(!image || NSEqualSizes([image size], rect.size)); - [image setFlipped:[view isFlipped]]; - [image drawInRect:rect - fromRect:NSZeroRect // Entire image - operation:NSCompositeSourceOver - fraction:1.0]; -} - -// Helper function to generate an attributed string containing -// |anImage|. If |baselineAdjustment| is 0, the image sits on the -// text baseline, positive values shift it up, negative values shift -// it down. -NSAttributedString* AttributedStringForImage(NSImage* anImage, - CGFloat baselineAdjustment) { - scoped_nsobject attachmentCell( - [[AutocompleteTextAttachmentCell alloc] initImageCell:anImage]); - scoped_nsobject attachment( - [[NSTextAttachment alloc] init]); - [attachment setAttachmentCell:attachmentCell]; - - scoped_nsobject as( - [[NSAttributedString attributedStringWithAttachment:attachment] - mutableCopy]); - [as addAttribute:NSBaselineOffsetAttributeName - value:[NSNumber numberWithFloat:baselineAdjustment] - range:NSMakeRange(0, [as length])]; - - return [[as copy] autorelease]; -} - } // namespace -@implementation AutocompleteTextAttachmentCell - -- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView { - // Draw image with |DrawImageInRect()| to get consistent - // |-setFlipped:| treatment. - DrawImageInRect([self image], aView, cellFrame); -} - -@end - @implementation AutocompleteTextFieldIcon @synthesize rect = rect_; @synthesize view = view_; -// Private helper. -- (id)initWithView:(LocationBarViewMac::LocationBarImageView*)view - isLabel:(BOOL)isLabel { - self = [super init]; - if (self) { - isLabel_ = isLabel; - view_ = view; - rect_ = NSZeroRect; - } - return self; -} - -- (id)initImageWithView:(LocationBarViewMac::LocationBarImageView*)view { - return [self initWithView:view isLabel:NO]; -} - -- (id)initLabelWithView:(LocationBarViewMac::LocationBarImageView*)view { - return [self initWithView:view isLabel:YES]; -} - -- (void)positionInFrame:(NSRect)frame { - if (isLabel_) { - NSAttributedString* label = view_->GetLabel(); - DCHECK(label); - const CGFloat labelWidth = ceil([label size].width); - rect_ = NSMakeRect(NSMaxX(frame) - labelWidth, - NSMinY(frame) + kIconLabelYOffset, - labelWidth, NSHeight(frame) - kIconLabelYOffset); - } else { - const NSSize imageSize = view_->GetImageSize(); - const CGFloat yOffset = floor((NSHeight(frame) - imageSize.height) / 2); - rect_ = NSMakeRect(NSMaxX(frame) - imageSize.width, - NSMinY(frame) + yOffset, - imageSize.width, imageSize.height); - } -} - -- (void)drawInView:(NSView*)controlView { - // Make sure someone called |-positionInFrame:|. - DCHECK(!NSIsEmptyRect(rect_)); - if (isLabel_) { - NSAttributedString* label = view_->GetLabel(); - [label drawInRect:rect_]; - } else { - DrawImageInRect(view_->GetImage(), controlView, rect_); - } ++ (AutocompleteTextFieldIcon*) + iconWithRect:(NSRect)rect + view:(LocationBarViewMac::LocationBarImageView*)view { + AutocompleteTextFieldIcon* result = [[AutocompleteTextFieldIcon alloc] init]; + [result setRect:rect]; + [result setView:view]; + return [result autorelease]; } @end @@ -205,40 +96,18 @@ NSAttributedString* AttributedStringForImage(NSImage* anImage, // Adjust for space between editor and decorations. width -= 2 * kEditorHorizontalInset; - // Get the magnifying glass to put at the front of the string. - NSImage* image = - AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_SEARCH); - const NSSize imageSize = [image size]; - - // Based on what fits, choose |fullString| with the image, - // |fullString| without the image, or |partialString|. + // If |fullString| won't fit, choose |partialString|. NSDictionary* attributes = [NSDictionary dictionaryWithObject:[self font] forKey:NSFontAttributeName]; NSString* s = fullString; - const CGFloat sWidth = [s sizeWithAttributes:attributes].width; - if (sWidth + imageSize.width > width) { - image = nil; - } - if (sWidth > width) { + if ([s sizeWithAttributes:attributes].width > width) { if (partialString) { s = partialString; } } - - scoped_nsobject as( - [[NSMutableAttributedString alloc] initWithString:s - attributes:attributes]); - - // Insert the image at the front of the string if it didn't make - // things too wide. - if (image) { - NSAttributedString* is = - AttributedStringForImage(image, kKeywordSearchImageBaseline); - [as insertAttributedString:is atIndex:0]; - } - - keywordString_.reset([as copy]); + keywordString_.reset( + [[NSAttributedString alloc] initWithString:s attributes:attributes]); } // Convenience for the attributes used in the right-justified info @@ -286,8 +155,21 @@ NSAttributedString* AttributedStringForImage(NSImage* anImage, initWithString:s attributes:[self hintAttributes]]); // Build an attachment containing the hint image. - NSAttributedString* is = - AttributedStringForImage(anImage, kKeywordHintImageBaseline); + scoped_nsobject attachmentCell( + [[NSTextAttachmentCell alloc] initImageCell:anImage]); + scoped_nsobject attachment( + [[NSTextAttachment alloc] init]); + [attachment setAttachmentCell:attachmentCell]; + + // The attachment's baseline needs to be adjusted so the image + // doesn't sit on the same baseline as the text and make + // everything too tall. + scoped_nsobject is( + [[NSAttributedString attributedStringWithAttachment:attachment] + mutableCopy]); + [is addAttribute:NSBaselineOffsetAttributeName + value:[NSNumber numberWithFloat:kKeywordHintImageBaseline] + range:NSMakeRange(0, [is length])]; // Stuff the image attachment between the prefix and suffix. [as insertAttributedString:is atIndex:[prefixString length]]; @@ -331,16 +213,8 @@ NSAttributedString* AttributedStringForImage(NSImage* anImage, page_action_views_ = list; } -- (void)setLocationIconView:(LocationBarViewMac::LocationIconView*)view { - locationIconView_ = view; -} - -- (void)setStarIconView:(LocationBarViewMac::LocationBarImageView*)view { - starIconView_ = view; -} - -- (void)setSecurityLabelView:(LocationBarViewMac::LocationBarImageView*)view { - securityLabelView_ = view; +- (void)setSecurityImageView:(LocationBarViewMac::SecurityImageView*)view { + security_image_view_ = view; } - (void)setContentSettingViewsList: @@ -352,81 +226,69 @@ NSAttributedString* AttributedStringForImage(NSImage* anImage, - (NSRect)textFrameForFrame:(NSRect)cellFrame { NSRect textFrame([super textFrameForFrame:cellFrame]); - // NOTE: This function must closely match the logic in - // |-drawInteriorWithFrame:inView:|. - - // Location icon is not shown in keyword search mode. - if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) { - const NSRect iconFrame = [self locationIconFrameForFrame:cellFrame]; - const CGFloat newOrigin = NSMaxX(iconFrame) + kLocationIconXPad; - textFrame.size.width = NSMaxX(textFrame) - newOrigin; - textFrame.origin.x = newOrigin; - } - - // Leave room for items on the right (SSL label, page actions, etc). - // Icons are laid out in |cellFrame| rather than |textFrame| for - // consistency with drawing code. - NSArray* icons = [self layedOutIcons:cellFrame]; - if ([icons count]) { - // Max x for resulting text frame. - const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]); - textFrame.size.width = maxX - NSMinX(textFrame); - } - - // Keyword string or hint string if they fit. - if (keywordString_) { - DCHECK(!hintString_); - const CGFloat keywordWidth(WidthForKeyword(keywordString_)); - - if (keywordWidth < NSWidth(textFrame)) { - textFrame.origin.x += keywordWidth; - textFrame.size.width -= keywordWidth; - } - } else if (hintString_) { + if (hintString_) { DCHECK(!keywordString_); const CGFloat hintWidth(WidthForHint(hintString_)); // TODO(shess): This could be better. Show the hint until the // non-hint text bumps against it? - if (hintWidth < NSWidth(textFrame)) { + if (hintWidth < NSWidth(cellFrame)) { textFrame.size.width -= hintWidth; } - } + } else if (keywordString_) { + DCHECK(!hintString_); + const CGFloat keywordWidth(WidthForKeyword(keywordString_)); - // SSL label if it fits. - if (securityLabelView_ && securityLabelView_->IsVisible() && - securityLabelView_->GetLabel()) { - NSAttributedString* label = securityLabelView_->GetLabel(); - const CGFloat labelWidth = ceil([label size].width) + kIconHorizontalPad; - if (NSWidth(textFrame) > labelWidth) { - textFrame.size.width -= labelWidth; + // TODO(shess): This could be better. There's support for a + // "short" version of the keyword string, work that in in a + // follow-on pass. + if (keywordWidth < NSWidth(cellFrame)) { + textFrame.origin.x += keywordWidth; + textFrame.size.width = NSMaxX(cellFrame) - NSMinX(textFrame); } + } else { + // Leave room for images on the right (lock icon etc). + NSArray* iconFrames = [self layedOutIcons:cellFrame]; + CGFloat width = 0; + if ([iconFrames count] > 0) + width = NSMaxX(cellFrame) - NSMinX([[iconFrames lastObject] rect]); + if (width > 0) + width += kIconHorizontalPad; + if (width < NSWidth(cellFrame)) + textFrame.size.width -= width; } return textFrame; } -- (NSRect)locationIconFrameForFrame:(NSRect)cellFrame { - if (!locationIconView_ || !locationIconView_->IsVisible()) - return NSZeroRect; - - const NSSize imageSize = locationIconView_->GetImageSize(); - const CGFloat yOffset = floor((NSHeight(cellFrame) - imageSize.height) / 2); - return NSMakeRect(NSMinX(cellFrame) + kLocationIconXOffset, - NSMinY(cellFrame) + yOffset, - imageSize.width, imageSize.height); +// Returns a rect of size |imageSize| centered vertically and right-justified in +// the |box|, with its top left corner |margin| pixels from the right end of the +// box. (The image thus occupies part of the |margin|.) +- (NSRect)rightJustifyImage:(NSSize)imageSize + inRect:(NSRect)box + withMargin:(CGFloat)margin { + box.origin.x += box.size.width - margin; + box.origin.y += floor((box.size.height - imageSize.height) / 2); + box.size = imageSize; + return box; } -- (NSRect)starIconFrameForFrame:(NSRect)cellFrame { - if (!starIconView_ || !starIconView_->IsVisible()) +- (NSRect)securityImageFrameForFrame:(NSRect)cellFrame { + if (!security_image_view_ || !security_image_view_->IsVisible()) { return NSZeroRect; + } + + // Calculate the total width occupied by the image, label, and padding. + NSSize imageSize = [security_image_view_->GetImage() size]; + CGFloat widthUsed = imageSize.width + kIconHorizontalPad; + NSAttributedString* label = security_image_view_->GetLabel(); + if (label) { + widthUsed += ceil([label size].width) + kHintXOffset; + } - // The star icon is always at the RHS. - scoped_nsobject icon( - [[AutocompleteTextFieldIcon alloc] initImageWithView:starIconView_]); - cellFrame.size.width -= kHintXOffset; - [icon positionInFrame:cellFrame]; - return [icon rect]; + return [self rightJustifyImage:imageSize + inRect:cellFrame + withMargin:widthUsed]; } - (size_t)pageActionCount { @@ -503,223 +365,118 @@ NSAttributedString* AttributedStringForImage(NSImage* anImage, [path stroke]; // Draw text w/in the rectangle. - infoFrame.origin.x += 3.0; + infoFrame.origin.x += 4.0; + infoFrame.origin.y += 1.0; [keywordString_.get() drawInRect:infoFrame]; } -- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - NSRect workingFrame = cellFrame; - - // NOTE: This function must closely match the logic in - // |-textFrameForFrame:|. - - // Location icon is not shown in keyword search mode. - if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) { - const NSRect iconFrame = [self locationIconFrameForFrame:cellFrame]; - DrawImageInRect(locationIconView_->GetImage(), controlView, iconFrame); - const CGFloat newOrigin = NSMaxX(iconFrame) + kLocationIconXPad; - workingFrame.size.width = NSMaxX(workingFrame) - newOrigin; - workingFrame.origin.x = newOrigin; - } - - NSArray* icons = [self layedOutIcons:cellFrame]; - for (AutocompleteTextFieldIcon* icon in icons) { - [icon drawInView:controlView]; - } - if ([icons count]) { - // Max x for resulting text frame. - const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]); - workingFrame.size.width = maxX - NSMinX(workingFrame); +- (void)drawImageView:(LocationBarViewMac::LocationBarImageView*)imageView + inFrame:(NSRect)imageFrame + inView:(NSView*)controlView { + // If there's a label, draw it to the right of the icon. The caller must have + // left sufficient space. + NSAttributedString* label = imageView->GetLabel(); + if (label) { + CGFloat labelWidth = ceil([label size].width) + kHintXOffset; + NSRect textFrame(NSMakeRect(NSMaxX(imageFrame) + kIconHorizontalPad, + imageFrame.origin.y + kIconLabelYOffset, + labelWidth, + imageFrame.size.height - kIconLabelYOffset)); + [label drawInRect:textFrame]; } - // Keyword string or hint string if they fit. - if (keywordString_) { - DCHECK(!hintString_); - const CGFloat keywordWidth(WidthForKeyword(keywordString_)); - - if (keywordWidth < NSWidth(workingFrame)) { - [self drawKeywordWithFrame:cellFrame inView:controlView]; - workingFrame.origin.x += keywordWidth; - workingFrame.size.width -= keywordWidth; - } - } else if (hintString_) { - DCHECK(!keywordString_); - const CGFloat hintWidth(WidthForHint(hintString_)); - - // TODO(shess): This could be better. Show the hint until the - // non-hint text bumps against it? - if (hintWidth < NSWidth(workingFrame)) { - [self drawHintWithFrame:cellFrame inView:controlView]; - workingFrame.size.width -= hintWidth; - } - } + // Draw the entire image. + NSRect imageRect = NSZeroRect; + NSImage* image = imageView->GetImage(); + image.size = [image size]; + [image setFlipped:[controlView isFlipped]]; + [image drawInRect:imageFrame + fromRect:imageRect + operation:NSCompositeSourceOver + fraction:1.0]; +} - // SSL label if it fits. - if (securityLabelView_ && securityLabelView_->IsVisible() && - securityLabelView_->GetLabel()) { - NSAttributedString* label = securityLabelView_->GetLabel(); - const CGFloat labelWidth = ceil([label size].width) + kIconHorizontalPad; - if (NSWidth(workingFrame) > labelWidth) { - workingFrame.size.width -= kIconHorizontalPad; - - scoped_nsobject icon( - [[AutocompleteTextFieldIcon alloc] - initLabelWithView:securityLabelView_]); - [icon positionInFrame:workingFrame]; - [icon drawInView:controlView]; - DCHECK_EQ(labelWidth, NSWidth([icon rect]) + kIconHorizontalPad); - workingFrame.size.width -= NSWidth([icon rect]); +- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { + if (hintString_) { + [self drawHintWithFrame:cellFrame inView:controlView]; + } else if (keywordString_) { + [self drawKeywordWithFrame:cellFrame inView:controlView]; + } else { + for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) { + [self drawImageView:[icon view] + inFrame:[icon rect] + inView:controlView]; } } - // Superclass draws text portion WRT original |cellFrame|. [super drawInteriorWithFrame:cellFrame inView:controlView]; } - (NSArray*)layedOutIcons:(NSRect)cellFrame { - // The set of views to display right-justified in the cell, from - // left to right. - NSMutableArray* result = [NSMutableArray array]; - - // Collect the image views for bulk processing. - // TODO(shess): Refactor with LocationBarViewMac to make the - // different types of items more consistent. - std::vector views; - - if (content_setting_views_) { - views.insert(views.end(), - content_setting_views_->begin(), - content_setting_views_->end()); - } - - // TODO(shess): Previous implementation of this method made a - // right-to-left array, so add the page-action items in that order. - // As part of the refactor mentioned above, lay everything out - // nicely left-to-right. - for (size_t i = [self pageActionCount]; i-- > 0;) { - views.push_back(page_action_views_->ViewAt(i)); + NSMutableArray* result = [NSMutableArray arrayWithCapacity:0]; + NSRect iconFrame = cellFrame; + if (security_image_view_ && security_image_view_->IsVisible()) { + NSRect securityImageFrame = [self securityImageFrameForFrame:iconFrame]; + [result addObject: + [AutocompleteTextFieldIcon iconWithRect:securityImageFrame + view:security_image_view_]]; + iconFrame.size.width -= NSMaxX(iconFrame) - NSMinX(securityImageFrame); } - // The star icon should always come last. - if (starIconView_) - views.push_back(starIconView_); - - // Load the visible views into |result|. - for (std::vector::const_iterator - iter = views.begin(); iter != views.end(); ++iter) { - if ((*iter)->IsVisible()) { - scoped_nsobject icon( - [[AutocompleteTextFieldIcon alloc] initImageWithView:*iter]); - [result addObject:icon]; + const size_t pageActionCount = [self pageActionCount]; + for (size_t i = 0; i < pageActionCount; ++i) { + LocationBarViewMac::PageActionImageView* view = + page_action_views_->ViewAt(i); + if (view->IsVisible()) { + // If this function is called right after a page action icon has been + // created, the images for all views will still be loading; in this case, + // each visible view will give us its default size. + NSSize iconSize = view->GetPreferredImageSize(); + NSRect pageActionFrame = + [self rightJustifyImage:iconSize + inRect:iconFrame + withMargin:kIconHorizontalPad + iconSize.width]; + [result addObject: + [AutocompleteTextFieldIcon iconWithRect:pageActionFrame view:view]]; + iconFrame.size.width -= NSMaxX(iconFrame) - NSMinX(pageActionFrame); } } - // Leave a boundary at RHS of field. - cellFrame.size.width -= kHintXOffset; - - // Position each view within the frame from right to left. - for (AutocompleteTextFieldIcon* icon in [result reverseObjectEnumerator]) { - [icon positionInFrame:cellFrame]; - - // Trim the icon's space from the frame. - cellFrame.size.width = NSMinX([icon rect]) - kIconHorizontalPad; + if (content_setting_views_) { + // We use a reverse_iterator here because we're laying out the views from + // right to left but in the vector they're ordered left to right. + for (LocationBarViewMac::ContentSettingViews::const_reverse_iterator + it(content_setting_views_->rbegin()); + it != const_cast( + content_setting_views_)->rend(); + ++it) { + if ((*it)->IsVisible()) { + NSImage* image = (*it)->GetImage(); + NSRect blockedContentFrame = + [self rightJustifyImage:[image size] + inRect:iconFrame + withMargin:[image size].width + kIconHorizontalPad]; + [result addObject: + [AutocompleteTextFieldIcon iconWithRect:blockedContentFrame + view:*it]]; + iconFrame.size.width -= NSMaxX(iconFrame) - NSMinX(blockedContentFrame); + } + } } return result; } -- (AutocompleteTextFieldIcon*)iconForEvent:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView { - const BOOL flipped = [controlView isFlipped]; - const NSPoint location = - [controlView convertPoint:[theEvent locationInWindow] fromView:nil]; - - // Special check for location image, it is not in |-layedOutIcons:|. - const NSRect locationIconFrame = [self locationIconFrameForFrame:cellFrame]; - if (NSMouseInRect(location, locationIconFrame, flipped)) { - // Make up an icon to return. - AutocompleteTextFieldIcon* icon = - [[[AutocompleteTextFieldIcon alloc] - initImageWithView:locationIconView_] autorelease]; - [icon setRect:locationIconFrame]; - return icon; - } - - for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) { - if (NSMouseInRect(location, [icon rect], flipped)) - return icon; - } - - return nil; -} - -- (NSMenu*)actionMenuForEvent:(NSEvent*)theEvent +- (NSMenu*)actionMenuForEvent:(NSEvent*)event inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView { - AutocompleteTextFieldIcon* - icon = [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; - if (icon) - return [icon view]->GetMenu(); - return nil; -} + ofView:(NSView*)aView { + NSPoint location = [aView convertPoint:[event locationInWindow] fromView:nil]; -- (BOOL)mouseDown:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView { - AutocompleteTextFieldIcon* icon = - [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; - if (!icon) - return NO; - - // If the icon is draggable, then initiate a drag if the user drags - // or holds the mouse down for awhile. - if ([icon view]->IsDraggable()) { - NSDate* timeout = - [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout]; - NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask | - NSLeftMouseUpMask) - untilDate:timeout - inMode:NSEventTrackingRunLoopMode - dequeue:YES]; - if (!event || [event type] == NSLeftMouseDragged) { - NSPasteboard* pboard = [icon view]->GetDragPasteboard(); - DCHECK(pboard); - - // TODO(shess): My understanding is that the -isFlipped - // adjustment should not be necessary. But without it, the - // image is nowhere near the cursor. Perhaps the icon's rect is - // incorrectly calculated? - // http://crbug.com/40711 - NSPoint dragPoint = [icon rect].origin; - if ([controlView isFlipped]) - dragPoint.y += NSHeight([icon rect]); - - [controlView dragImage:[icon view]->GetImage() - at:dragPoint - offset:NSZeroSize - event:event ? event : theEvent - pasteboard:pboard - source:self - slideBack:YES]; - return YES; + const BOOL flipped = [aView isFlipped]; + for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) { + if (NSMouseInRect(location, [icon rect], flipped)) { + return [icon view]->GetMenu(); } - - // On mouse-up fall through to mouse-pressed case. - DCHECK_EQ([event type], NSLeftMouseUp); } - - [icon view]->OnMousePressed([icon rect]); - return YES; -} - -- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { - return NSDragOperationCopy; -} - -- (NSPasteboard*)locationDragPasteboard { - if (locationIconView_ && locationIconView_->IsDraggable()) - return locationIconView_->GetDragPasteboard(); - return nil; } diff --git a/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm b/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm index 5bd02cc..0a16c48 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm @@ -4,11 +4,9 @@ #import -#include "app/resource_bundle.h" #include "base/scoped_nsobject.h" #import "chrome/browser/cocoa/autocomplete_text_field_cell.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" -#include "grit/theme_resources.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -45,7 +43,7 @@ class TestPageActionViewList : public LocationBarViewMac::PageActionViewList { class AutocompleteTextFieldCellTest : public CocoaTest { public: - AutocompleteTextFieldCellTest() : location_icon_view_(NULL), + AutocompleteTextFieldCellTest() : security_image_view_(NULL, NULL, NULL), page_action_views_() { // Make sure this is wide enough to play games with the cell // decorations. @@ -59,8 +57,7 @@ class AutocompleteTextFieldCellTest : public CocoaTest { [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]); [cell setEditable:YES]; [cell setBordered:YES]; - [cell setLocationIconView:&location_icon_view_]; - [cell setSecurityLabelView:&security_label_view_]; + [cell setSecurityImageView:&security_image_view_]; [cell setPageActionViewList:&page_action_views_]; [view_ setCell:cell.get()]; @@ -68,8 +65,7 @@ class AutocompleteTextFieldCellTest : public CocoaTest { } NSTextField* view_; - LocationBarViewMac::LocationIconView location_icon_view_; - LocationBarViewMac::LocationBarImageView security_label_view_; + LocationBarViewMac::SecurityImageView security_image_view_; TestPageActionViewList page_action_views_; }; @@ -203,16 +199,15 @@ TEST_F(AutocompleteTextFieldCellTest, TextFrame) { EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame)); EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); - // Location icon takes up space on the left - location_icon_view_.SetImage( - ResourceBundle::GetSharedInstance().GetNSImageNamed( - IDR_OMNIBOX_HTTPS_VALID)); - location_icon_view_.SetVisible(true); + // Security icon takes up space on the right + security_image_view_.SetImageShown( + LocationBarViewMac::SecurityImageView::LOCK); + security_image_view_.SetVisible(true); textFrame = [cell textFrameForFrame:bounds]; EXPECT_FALSE(NSIsEmptyRect(textFrame)); EXPECT_TRUE(NSContainsRect(bounds, textFrame)); - EXPECT_GT(NSMinX(textFrame), NSMinX(bounds)); + EXPECT_LT(NSMaxX(textFrame), NSMaxX(bounds)); EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); // Search hint text takes precedence over the hint icon; the text frame @@ -270,10 +265,9 @@ TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) { EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); EXPECT_TRUE(NSEqualRects(drawingRect, originalDrawingRect)); - location_icon_view_.SetImage( - ResourceBundle::GetSharedInstance().GetNSImageNamed( - IDR_OMNIBOX_HTTPS_VALID)); - location_icon_view_.SetVisible(true); + security_image_view_.SetImageShown( + LocationBarViewMac::SecurityImageView::LOCK); + security_image_view_.SetVisible(true); textFrame = [cell textFrameForFrame:bounds]; drawingRect = [cell drawingRectForBounds:bounds]; @@ -281,60 +275,55 @@ TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) { EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); } -// Test that the location icon is at the right side of the cell. -TEST_F(AutocompleteTextFieldCellTest, LocationIconFrame) { +// Test that the security icon is at the right side of the cell. +TEST_F(AutocompleteTextFieldCellTest, SecurityImageFrame) { AutocompleteTextFieldCell* cell = static_cast([view_ cell]); const NSRect bounds([view_ bounds]); - location_icon_view_.SetImage( - ResourceBundle::GetSharedInstance().GetNSImageNamed( - IDR_OMNIBOX_HTTPS_VALID)); + security_image_view_.SetImageShown( + LocationBarViewMac::SecurityImageView::LOCK); - location_icon_view_.SetVisible(true); - const NSRect iconRect = [cell locationIconFrameForFrame:bounds]; - EXPECT_FALSE(NSIsEmptyRect(iconRect)); - EXPECT_TRUE(NSContainsRect(bounds, iconRect)); + security_image_view_.SetVisible(false); + EXPECT_EQ(0u, [[cell layedOutIcons:bounds] count]); - // Location icon should be left of |drawingRect|. - const NSRect drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_GT(NSMinX(drawingRect), NSMinX(iconRect)); + security_image_view_.SetVisible(true); + NSArray* icons = [cell layedOutIcons:bounds]; + ASSERT_EQ(1u, [icons count]); + NSRect iconRect = [[icons objectAtIndex:0] rect]; - // Location icon should be left of |textFrame|. - const NSRect textFrame = [cell textFrameForFrame:bounds]; - EXPECT_GT(NSMinX(textFrame), NSMinX(iconRect)); -} + EXPECT_FALSE(NSIsEmptyRect(iconRect)); + EXPECT_TRUE(NSContainsRect(bounds, iconRect)); -// Test that security label takes space to the right. -TEST_F(AutocompleteTextFieldCellTest, SecurityLabelFrame) { - AutocompleteTextFieldCell* cell = - static_cast([view_ cell]); - const NSRect bounds([view_ bounds]); + // Make sure we are right of the |drawingRect|. + NSRect drawingRect = [cell drawingRectForBounds:bounds]; + EXPECT_LE(NSMaxX(drawingRect), NSMinX(iconRect)); - // No label shows nothing, regardless of visibility setting. - security_label_view_.SetVisible(false); - const NSRect baseTextFrame = [cell textFrameForFrame:bounds]; - security_label_view_.SetVisible(true); - EXPECT_TRUE(NSEqualRects(baseTextFrame, [cell textFrameForFrame:bounds])); + // Make sure we're right of the |textFrame|. + NSRect textFrame = [cell textFrameForFrame:bounds]; + EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect)); - // Still not visible even with a label. + // Now add a label. NSFont* font = [NSFont controlContentFontOfSize:12.0]; NSColor* color = [NSColor blackColor]; - security_label_view_.SetLabel(@"Label", font, color); - security_label_view_.SetVisible(false); - EXPECT_TRUE(NSEqualRects(baseTextFrame, [cell textFrameForFrame:bounds])); + security_image_view_.SetLabel(@"Label", font, color); + icons = [cell layedOutIcons:bounds]; + ASSERT_EQ(1u, [icons count]); + iconRect = [[icons objectAtIndex:0] rect]; - // Visible with a label is strictly narrower than without. - security_label_view_.SetVisible(true); - NSRect textFrame = [cell textFrameForFrame:bounds]; - const CGFloat labelWidth = [security_label_view_.GetLabel() size].width; - EXPECT_TRUE(NSContainsRect(baseTextFrame, textFrame)); - EXPECT_LT(NSWidth(textFrame), NSWidth(baseTextFrame) - labelWidth); + EXPECT_FALSE(NSIsEmptyRect(iconRect)); + EXPECT_TRUE(NSContainsRect(bounds, iconRect)); - NSString* longLabel = - @"Really super-long labels will not show up if there's not enough room."; - security_label_view_.SetLabel(longLabel, font, color); + // Make sure we are right of the |drawingRect|. + drawingRect = [cell drawingRectForBounds:bounds]; + EXPECT_LE(NSMaxX(drawingRect), NSMinX(iconRect)); + + // Make sure we're right of the |textFrame|. textFrame = [cell textFrameForFrame:bounds]; - EXPECT_TRUE(NSEqualRects(baseTextFrame, [cell textFrameForFrame:bounds])); + EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect)); + + // Make sure we clear correctly. + security_image_view_.SetVisible(false); + EXPECT_EQ(0u, [[cell layedOutIcons:bounds] count]); } // Test Page Action counts. @@ -360,6 +349,8 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { AutocompleteTextFieldCell* cell = static_cast([view_ cell]); const NSRect bounds([view_ bounds]); + security_image_view_.SetImageShown( + LocationBarViewMac::SecurityImageView::LOCK); TestPageActionImageView page_action_view; // We'll assume that the extensions code enforces icons smaller than the @@ -377,12 +368,13 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { list.Add(&page_action_view2); [cell setPageActionViewList:&list]; + security_image_view_.SetVisible(false); page_action_view.SetVisible(false); page_action_view2.SetVisible(false); EXPECT_TRUE(NSIsEmptyRect([cell pageActionFrameForIndex:0 inFrame:bounds])); EXPECT_TRUE(NSIsEmptyRect([cell pageActionFrameForIndex:1 inFrame:bounds])); - // One page action, no lock icon. + // One page action, no security icon. page_action_view.SetVisible(true); NSRect iconRect0 = [cell pageActionFrameForIndex:0 inFrame:bounds]; @@ -397,19 +389,17 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { NSRect textFrame = [cell textFrameForFrame:bounds]; EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect0)); - // Two page actions plus a security label. + // Two page actions plus a security icon. page_action_view2.SetVisible(true); + security_image_view_.SetVisible(true); NSArray* icons = [cell layedOutIcons:bounds]; - ASSERT_EQ(2u, [icons count]); - - // TODO(shess): page-action list is inverted from -layedOutIcons: - // Yes, this is confusing, fix it. + EXPECT_EQ(3u, [icons count]); iconRect0 = [cell pageActionFrameForIndex:0 inFrame:bounds]; NSRect iconRect1 = [cell pageActionFrameForIndex:1 inFrame:bounds]; - NSRect labelRect = [[icons objectAtIndex:0] rect]; + NSRect lockRect = [[icons objectAtIndex:0] rect]; EXPECT_TRUE(NSEqualRects(iconRect0, [[icons objectAtIndex:1] rect])); - EXPECT_TRUE(NSEqualRects(iconRect1, [[icons objectAtIndex:0] rect])); + EXPECT_TRUE(NSEqualRects(iconRect1, [[icons objectAtIndex:2] rect])); // Make sure they're all in the expected order, and right of the |drawingRect| // and |textFrame|. @@ -420,13 +410,13 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { EXPECT_TRUE(NSContainsRect(bounds, iconRect0)); EXPECT_FALSE(NSIsEmptyRect(iconRect1)); EXPECT_TRUE(NSContainsRect(bounds, iconRect1)); - EXPECT_FALSE(NSIsEmptyRect(labelRect)); - EXPECT_TRUE(NSContainsRect(bounds, labelRect)); + EXPECT_FALSE(NSIsEmptyRect(lockRect)); + EXPECT_TRUE(NSContainsRect(bounds, lockRect)); EXPECT_LE(NSMaxX(drawingRect), NSMinX(iconRect1)); EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect1)); EXPECT_LE(NSMaxX(iconRect1), NSMinX(iconRect0)); - EXPECT_LE(NSMaxX(labelRect), NSMinX(iconRect0)); + EXPECT_LE(NSMaxX(iconRect0), NSMinX(lockRect)); } // Test that the cell correctly chooses the partial keyword if there's @@ -438,22 +428,11 @@ TEST_F(AutocompleteTextFieldCellTest, UsesPartialKeywordIfNarrow) { const NSString* kFullString = @"Search Engine:"; const NSString* kPartialString = @"Search Eng:"; - // Wide width chooses the full string, including an image on the - // left. + // Wide width chooses the full string. [cell setKeywordString:kFullString partialString:kPartialString availableWidth:kWidth]; EXPECT_TRUE([cell keywordString]); - EXPECT_TRUE([[[cell keywordString] string] hasSuffix:kFullString]); - EXPECT_TRUE([[cell keywordString] containsAttachments]); - - // If not enough space to include the image, uses exactly the full - // string. - CGFloat allWidth = [[cell keywordString] size].width; - [cell setKeywordString:kFullString - partialString:kPartialString - availableWidth:allWidth - 5.0]; - EXPECT_TRUE([cell keywordString]); EXPECT_TRUE([[[cell keywordString] string] isEqualToString:kFullString]); // Narrow width chooses the partial string. diff --git a/chrome/browser/cocoa/autocomplete_text_field_editor.mm b/chrome/browser/cocoa/autocomplete_text_field_editor.mm index 974b346..70aa5cd 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_editor.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_editor.mm @@ -33,35 +33,6 @@ class Extension; return self; } -// If the entire field is selected, drag the same data as would be -// dragged from the field's location icon. In some cases the textual -// contents will not contain relevant data (for instance, "http://" is -// stripped from URLs). -- (BOOL)dragSelectionWithEvent:(NSEvent *)event - offset:(NSSize)mouseOffset - slideBack:(BOOL)slideBack { - const NSRange allRange = NSMakeRange(0, [[self textStorage] length]); - if (NSEqualRanges(allRange, [self selectedRange])) { - NSPasteboard* pboard = [[self delegate] locationDragPasteboard]; - if (pboard) { - NSPoint p; - NSImage* image = [self dragImageForSelectionWithEvent:event origin:&p]; - - [self dragImage:image - at:p - offset:mouseOffset - event:event - pasteboard:pboard - source:self - slideBack:slideBack]; - return YES; - } - } - return [super dragSelectionWithEvent:event - offset:mouseOffset - slideBack:slideBack]; -} - - (void)copy:(id)sender { AutocompleteTextFieldObserver* observer = [self observer]; DCHECK(observer); diff --git a/chrome/browser/cocoa/autocomplete_text_field_unittest.mm b/chrome/browser/cocoa/autocomplete_text_field_unittest.mm index 1d0ae49..d695f86 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_unittest.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_unittest.mm @@ -4,7 +4,6 @@ #import -#include "app/resource_bundle.h" #import "base/cocoa_protocols_mac.h" #include "base/scoped_nsobject.h" #import "chrome/browser/cocoa/autocomplete_text_field.h" @@ -12,7 +11,6 @@ #import "chrome/browser/cocoa/autocomplete_text_field_editor.h" #import "chrome/browser/cocoa/autocomplete_text_field_unittest_helper.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" -#include "grit/theme_resources.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -22,34 +20,18 @@ using ::testing::Return; using ::testing::StrictMock; namespace { -class MockLocationIconView : public LocationBarViewMac::LocationIconView { +class MockSecurityImageView : public LocationBarViewMac::SecurityImageView { public: - MockLocationIconView() - : LocationBarViewMac::LocationIconView(NULL), - is_draggable_(false), - mouse_was_pressed_(false) {} - - // |LocationBarViewMac::LocationIconView| dragging support needs - // more setup than this test provides. - bool IsDraggable() { - return is_draggable_; - } - virtual NSPasteboard* GetDragPasteboard() { - return [NSPasteboard pasteboardWithUniqueName]; - } - void SetDraggable(bool is_draggable) { - is_draggable_ = is_draggable; - } + MockSecurityImageView(LocationBarViewMac* owner, + Profile* profile, + ToolbarModel* model) + : LocationBarViewMac::SecurityImageView(owner, profile, model) {} // We can't use gmock's MOCK_METHOD macro, because it doesn't like the // NSRect argument to OnMousePressed. virtual void OnMousePressed(NSRect bounds) { mouse_was_pressed_ = true; } - bool MouseWasPressed() { return mouse_was_pressed_; } - - private: - bool is_draggable_; bool mouse_was_pressed_; }; @@ -600,35 +582,32 @@ TEST_F(AutocompleteTextFieldTest, TripleClickSelectsAll) { } // Clicking the security icon should call its OnMousePressed. -TEST_F(AutocompleteTextFieldTest, LocationIconMouseDown) { +TEST_F(AutocompleteTextFieldObserverTest, SecurityIconMouseDown) { AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; - MockLocationIconView location_icon_view; - [cell setLocationIconView:&location_icon_view]; - location_icon_view.SetImage( - ResourceBundle::GetSharedInstance().GetNSImageNamed( - IDR_OMNIBOX_HTTPS_VALID)); - location_icon_view.SetVisible(true); + MockSecurityImageView security_image_view(NULL, NULL, NULL); + [cell setSecurityImageView:&security_image_view]; + security_image_view.SetImageShown( + LocationBarViewMac::SecurityImageView::LOCK); + security_image_view.SetVisible(true); - NSRect iconFrame([cell locationIconFrameForFrame:[field_ bounds]]); + NSRect iconFrame([cell securityImageFrameForFrame:[field_ bounds]]); NSPoint location(NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame))); - NSEvent* downEvent(Event(field_, location, NSLeftMouseDown, 1)); - NSEvent* upEvent(Event(field_, location, NSLeftMouseUp, 1)); - - // Since location icon can be dragged, the mouse-press is sent on - // mouse-up. - [NSApp postEvent:upEvent atStart:YES]; - [field_ mouseDown:downEvent]; - EXPECT_TRUE(location_icon_view.MouseWasPressed()); + NSEvent* event(Event(field_, location, NSLeftMouseDown, 1)); - // TODO(shess): Test that mouse drags are initiated if the next - // event is a drag, or if the mouse-up takes too long to arrive. + [field_ mouseDown:event]; + EXPECT_TRUE(security_image_view.mouse_was_pressed_); } // Clicking a Page Action icon should call its OnMousePressed. -TEST_F(AutocompleteTextFieldTest, PageActionMouseDown) { +TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; + MockSecurityImageView security_image_view(NULL, NULL, NULL); + security_image_view.SetImageShown( + LocationBarViewMac::SecurityImageView::LOCK); + [cell setSecurityImageView:&security_image_view]; + MockPageActionImageView page_action_view; NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"]; page_action_view.SetImage(image); @@ -641,7 +620,8 @@ TEST_F(AutocompleteTextFieldTest, PageActionMouseDown) { list.Add(&page_action_view2); [cell setPageActionViewList:&list]; - // One page action. + // One page action, no security lock. + security_image_view.SetVisible(false); page_action_view.SetVisible(true); page_action_view2.SetVisible(false); NSRect iconFrame([cell pageActionFrameForIndex:0 inFrame:[field_ bounds]]); @@ -651,7 +631,7 @@ TEST_F(AutocompleteTextFieldTest, PageActionMouseDown) { [field_ mouseDown:event]; EXPECT_TRUE(page_action_view.MouseWasPressed()); - // Two page actions, no lock. + // Two page actions, no security lock. page_action_view2.SetVisible(true); iconFrame = [cell pageActionFrameForIndex:0 inFrame:[field_ bounds]]; location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); @@ -667,7 +647,8 @@ TEST_F(AutocompleteTextFieldTest, PageActionMouseDown) { [field_ mouseDown:event]; EXPECT_TRUE(page_action_view.MouseWasPressed()); - // Two page actions. + // Two page actions plus security lock. + security_image_view.SetVisible(true); iconFrame = [cell pageActionFrameForIndex:0 inFrame:[field_ bounds]]; location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); event = Event(field_, location, NSLeftMouseDown, 1); @@ -681,6 +662,13 @@ TEST_F(AutocompleteTextFieldTest, PageActionMouseDown) { [field_ mouseDown:event]; EXPECT_TRUE(page_action_view.MouseWasPressed()); + + iconFrame = [cell securityImageFrameForFrame:[field_ bounds]]; + location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); + event = Event(field_, location, NSLeftMouseDown, 1); + + [field_ mouseDown:event]; + EXPECT_TRUE(security_image_view.mouse_was_pressed_); } // Test that page action menus are properly returned. @@ -872,22 +860,4 @@ TEST_F(AutocompleteTextFieldObserverTest, SendsOnResignKey) { [test_window() resignKeyWindow]; } -TEST_F(AutocompleteTextFieldTest, LocationDragPasteboard) { - AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; - - MockLocationIconView location_icon_view; - location_icon_view.SetImage( - ResourceBundle::GetSharedInstance().GetNSImageNamed( - IDR_OMNIBOX_HTTPS_VALID)); - location_icon_view.SetVisible(true); - [cell setLocationIconView:&location_icon_view]; - - // Not draggable, so no pasteboard. - EXPECT_FALSE([field_ locationDragPasteboard]); - - // Gets a pasteboard when draggable. - location_icon_view.SetDraggable(true); - EXPECT_TRUE([field_ locationDragPasteboard]); -} - } // namespace diff --git a/chrome/browser/cocoa/bookmark_bubble_controller.mm b/chrome/browser/cocoa/bookmark_bubble_controller.mm index 465691e..fc2ff7b 100644 --- a/chrome/browser/cocoa/bookmark_bubble_controller.mm +++ b/chrome/browser/cocoa/bookmark_bubble_controller.mm @@ -98,7 +98,7 @@ [BrowserWindowController browserWindowControllerForWindow:parentWindow_]; [bwc lockBarVisibilityForOwner:self withAnimation:NO delay:NO]; NSWindow* window = [self window]; // completes nib load - [bubble_ setArrowLocation:kTopRight]; + [bubble_ setArrowLocation:kTopLeft]; // Insure decent positioning even in the absence of a browser controller, // which will occur for some unit tests. NSPoint arrowtip = bwc ? [bwc pointForBubbleArrowTip] : diff --git a/chrome/browser/cocoa/browser_test_helper.h b/chrome/browser/cocoa/browser_test_helper.h index b7e3e64..0420c7a 100644 --- a/chrome/browser/cocoa/browser_test_helper.h +++ b/chrome/browser/cocoa/browser_test_helper.h @@ -25,15 +25,6 @@ class BrowserTestHelper { profile_.reset(new TestingProfile()); profile_->CreateBookmarkModel(true); profile_->BlockUntilBookmarkModelLoaded(); - - // TODO(shess): These are needed in case someone creates a browser - // window off of browser_. pkasting indicates that other - // platforms use a stub |BrowserWindow| and thus don't need to do - // this. - // http://crbug.com/39725 - profile_->CreateAutocompleteClassifier(); - profile_->CreateTemplateURLModel(); - browser_.reset(new Browser(Browser::TYPE_NORMAL, profile_.get())); } diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index ceee615..101807d 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -1375,7 +1375,7 @@ } - (NSPoint)pointForBubbleArrowTip { - NSRect rect = [toolbarController_ starIconInWindowCoordinates]; + NSRect rect = [toolbarController_ starButtonInWindowCoordinates]; // Determine the point of the arrow of the bubble window. NSPoint p = rect.origin; p.x += (NSWidth(rect) / 2.0) + 1.0; // Star is not exactly in center. diff --git a/chrome/browser/cocoa/browser_window_controller_unittest.mm b/chrome/browser/cocoa/browser_window_controller_unittest.mm index d6a3dca..5b054fa 100644 --- a/chrome/browser/cocoa/browser_window_controller_unittest.mm +++ b/chrome/browser/cocoa/browser_window_controller_unittest.mm @@ -437,10 +437,10 @@ TEST_F(BrowserWindowControllerTest, TestTopRightForBubble) { NSPoint p = [controller_ pointForBubbleArrowTip]; NSRect all = [[controller_ window] frame]; - // As a sanity check make sure the point is vaguely in the top right + // As a sanity check make sure the point is vaguely in the top left // of the window. EXPECT_GT(p.y, all.origin.y + (all.size.height/2)); - EXPECT_GT(p.x, all.origin.x + (all.size.width/2)); + EXPECT_LT(p.x, all.origin.x + (all.size.width/2)); } // By the "zoom frame", we mean what Apple calls the "standard frame". diff --git a/chrome/browser/cocoa/location_bar_view_mac.h b/chrome/browser/cocoa/location_bar_view_mac.h index 66584f0..2107ec3 100644 --- a/chrome/browser/cocoa/location_bar_view_mac.h +++ b/chrome/browser/cocoa/location_bar_view_mac.h @@ -24,6 +24,7 @@ #include "third_party/skia/include/core/SkBitmap.h" @class AutocompleteTextField; +class BubblePositioner; class CommandUpdater; class ContentSettingImageModel; @class ExtensionPopupController; @@ -40,6 +41,7 @@ class LocationBarViewMac : public AutocompleteEditController, public NotificationObserver { public: LocationBarViewMac(AutocompleteTextField* field, + const BubblePositioner* bubble_positioner, CommandUpdater* command_updater, ToolbarModel* toolbar_model, Profile* profile, @@ -62,9 +64,6 @@ class LocationBarViewMac : public AutocompleteEditController, virtual void InvalidatePageActions(); virtual void SaveStateToContents(TabContents* contents); virtual void Revert(); - virtual const AutocompleteEditView* location_entry() const { - return edit_view_.get(); - } virtual AutocompleteEditView* location_entry() { return edit_view_.get(); } @@ -77,13 +76,6 @@ class LocationBarViewMac : public AutocompleteEditController, virtual ExtensionAction* GetVisiblePageAction(size_t index); virtual void TestPageActionPressed(size_t index); - // Set/Get the editable state of the field. - void SetEditable(bool editable); - bool IsEditable(); - - // Set the starred state of the bookmark star. - void SetStarred(bool starred); - // Updates the location bar. Resets the bar's permanent text and // security style, and if |should_restore_state| is true, restores // saved state from the tab (for tab switching). @@ -132,6 +124,7 @@ class LocationBarViewMac : public AutocompleteEditController, const std::wstring& keyword, const std::wstring& short_name, const bool is_keyword_hint, + const bool show_search_hint, NSImage* image); // Overridden from NotificationObserver. @@ -149,9 +142,7 @@ class LocationBarViewMac : public AutocompleteEditController, // Sets the image. void SetImage(NSImage* image); - - // Get the |resource_id| image resource and set the image. - void SetIcon(int resource_id); + void SetImage(SkBitmap* image); // Sets the label text, font, and color. |text| may be nil; |color| and // |font| are ignored if |text| is nil. @@ -165,21 +156,9 @@ class LocationBarViewMac : public AutocompleteEditController, const NSAttributedString* GetLabel() const { return label_; } bool IsVisible() const { return visible_; } - // Default size when no image is present. - virtual NSSize GetDefaultImageSize() const; - - // Returns the size of the image, else the default size. - NSSize GetImageSize() const; - // Returns the tooltip for this image view or |nil| if there is none. virtual const NSString* GetToolTip() { return nil; } - // Used to determinate if the item can act as a drag source. - virtual bool IsDraggable() { return false; } - - // The drag pasteboard to use if a drag is initiated. - virtual NSPasteboard* GetDragPasteboard() { return nil; } - // Called on mouse down. virtual void OnMousePressed(NSRect bounds) {} @@ -197,50 +176,42 @@ class LocationBarViewMac : public AutocompleteEditController, DISALLOW_COPY_AND_ASSIGN(LocationBarImageView); }; - // LocationIconView is used to display an icon to the left of the address. - class LocationIconView : public LocationBarImageView { + // SecurityImageView is used to display the lock or warning icon when the + // current URL's scheme is https. + class SecurityImageView : public LocationBarImageView { public: - explicit LocationIconView(LocationBarViewMac* owner); - virtual ~LocationIconView(); + enum Image { + LOCK = 0, + WARNING + }; - // Is draggable if the autocomplete edit view has not be changed. - virtual bool IsDraggable(); + SecurityImageView(LocationBarViewMac* owner, + Profile* profile, + ToolbarModel* model); + virtual ~SecurityImageView(); - // Drag the URL and title from the current tab. - virtual NSPasteboard* GetDragPasteboard(); + // Sets the image to the appropriate icon. + void SetImageShown(Image image); // Shows the page info dialog. virtual void OnMousePressed(NSRect bounds); private: - // The location bar view that owns us. - LocationBarViewMac* owner_; + // The lock icon shown when using HTTPS. Loaded lazily, the first time it's + // needed. + scoped_nsobject lock_icon_; - DISALLOW_COPY_AND_ASSIGN(LocationIconView); - }; - - // Used to display the bookmark star in the RHS. - class StarIconView : public LocationBarImageView { - public: - explicit StarIconView(CommandUpdater* command_updater); - virtual ~StarIconView() {} + // The warning icon shown when HTTPS is broken. Loaded lazily, the first + // time it's needed. + scoped_nsobject warning_icon_; - // Shows the bookmark bubble. - virtual void OnMousePressed(NSRect bounds); - - // Set the image and tooltip based on |starred|. - void SetStarred(bool starred); - - virtual const NSString* GetToolTip(); - - private: - // For bringing up bookmark bar. - CommandUpdater* command_updater_; // Weak, owned by Browser. + // The location bar view that owns us. + LocationBarViewMac* owner_; - // The string to show for a tooltip. - scoped_nsobject tooltip_; + Profile* profile_; + ToolbarModel* model_; - DISALLOW_COPY_AND_ASSIGN(StarIconView); + DISALLOW_COPY_AND_ASSIGN(SecurityImageView); }; // PageActionImageView is used to display the icon for a given Page Action @@ -260,13 +231,14 @@ class LocationBarViewMac : public AutocompleteEditController, void set_preview_enabled(bool enabled) { preview_enabled_ = enabled; } - bool preview_enabled() const { return preview_enabled_; } + bool preview_enabled() { return preview_enabled_; } + // Returns the size of the image, or a default size if no image available. // When a new page action is created, all the icons are destroyed and // recreated; at this point we need to calculate sizes to lay out the // icons even though no images are available yet. For this case, we return // the default image size for a page icon. - virtual NSSize GetDefaultImageSize() const; + virtual NSSize GetPreferredImageSize(); // Either notify listeners or show a popup depending on the Page Action. virtual void OnMousePressed(NSRect bounds); @@ -412,11 +384,11 @@ class LocationBarViewMac : public AutocompleteEditController, }; private: - // Sets the location icon we should be showing. - void SetIcon(int resource_id); + // Sets the SSL icon we should be showing. + void SetSecurityIcon(ToolbarModel::Icon icon); - // Sets the label for the SSL state. - void SetSecurityLabel(); + // Sets the label for the SSL icon. + void SetSecurityIconLabel(); // Posts |notification| to the default notification center. void PostNotification(const NSString* notification); @@ -439,14 +411,8 @@ class LocationBarViewMac : public AutocompleteEditController, // The user's desired disposition for how their input should be opened. WindowOpenDisposition disposition_; - // A view that shows an icon to the left of the address. - LocationIconView location_icon_view_; - - // Security info as text which floats left of the page actions. - LocationBarImageView security_label_view_; - - // Bookmark star right of page actions. - StarIconView star_icon_view_; + // The view that shows the lock/warning when in HTTPS mode. + SecurityImageView security_image_view_; // Any installed Page Actions. PageActionViewList page_action_views_; diff --git a/chrome/browser/cocoa/location_bar_view_mac.mm b/chrome/browser/cocoa/location_bar_view_mac.mm index 6e33130..62b12d4 100644 --- a/chrome/browser/cocoa/location_bar_view_mac.mm +++ b/chrome/browser/cocoa/location_bar_view_mac.mm @@ -41,7 +41,6 @@ #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "skia/ext/skia_utils_mac.h" -#import "third_party/mozilla/NSPasteboard+Utils.h" // TODO(shess): This code is mostly copied from the gtk @@ -63,13 +62,11 @@ std::wstring GetKeywordName(Profile* profile, const std::wstring& keyword) { return std::wstring(); } -// Values for the label colors for different security states. -static const CGFloat kEVSecureTextColorRedComponent = 0.03; -static const CGFloat kEVSecureTextColorGreenComponent = 0.58; -static const CGFloat kEVSecureTextColorBlueComponent = 0.0; -static const CGFloat kSecurityErrorTextColorRedComponent = 0.63; -static const CGFloat kSecurityErrorTextColorGreenComponent = 0.0; -static const CGFloat kSecurityErrorTextColorBlueComponent = 0.0; +// Values for the green text color displayed for EV certificates, based +// on the values for kEvTextColor in location_bar_view_gtk.cc. +static const CGFloat kEvTextColorRedComponent = 0.0; +static const CGFloat kEvTextColorGreenComponent = 0.59; +static const CGFloat kEvTextColorBlueComponent = 0.08; // Build a short string to use in keyword-search when the field isn't // very big. @@ -94,18 +91,17 @@ std::wstring CalculateMinString(const std::wstring& description) { LocationBarViewMac::LocationBarViewMac( AutocompleteTextField* field, + const BubblePositioner* bubble_positioner, CommandUpdater* command_updater, ToolbarModel* toolbar_model, Profile* profile, Browser* browser) - : edit_view_(new AutocompleteEditViewMac(this, toolbar_model, profile, - command_updater, field)), + : edit_view_(new AutocompleteEditViewMac(this, bubble_positioner, + toolbar_model, profile, command_updater, field)), command_updater_(command_updater), field_(field), disposition_(CURRENT_TAB), - location_icon_view_(this), - security_label_view_(), - star_icon_view_(command_updater), + security_image_view_(this, profile, toolbar_model), page_action_views_(this, profile, toolbar_model), profile_(profile), browser_(browser), @@ -120,9 +116,7 @@ LocationBarViewMac::LocationBarViewMac( } AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; - [cell setLocationIconView:&location_icon_view_]; - [cell setSecurityLabelView:&security_label_view_]; - [cell setStarIconView:&star_icon_view_]; + [cell setSecurityImageView:&security_image_view_]; [cell setPageActionViewList:&page_action_views_]; [cell setContentSettingViewsList:&content_setting_views_]; @@ -135,9 +129,7 @@ LocationBarViewMac::~LocationBarViewMac() { // Disconnect from cell in case it outlives us. AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; [cell setPageActionViewList:NULL]; - [cell setLocationIconView:NULL]; - [cell setSecurityLabelView:NULL]; - [cell setStarIconView:NULL]; + [cell setSecurityImageView:NULL]; } std::wstring LocationBarViewMac::GetInputString() const { @@ -214,7 +206,7 @@ void LocationBarViewMac::SaveStateToContents(TabContents* contents) { void LocationBarViewMac::Update(const TabContents* contents, bool should_restore_state) { - SetIcon(edit_view_->GetIcon()); + SetSecurityIcon(toolbar_model_->GetIcon()); page_action_views_.RefreshViews(); RefreshContentSettingsViews(); // AutocompleteEditView restores state if the tab is non-NULL. @@ -260,6 +252,7 @@ void LocationBarViewMac::OnChangedImpl(AutocompleteTextField* field, const std::wstring& keyword, const std::wstring& short_name, const bool is_keyword_hint, + const bool show_search_hint, NSImage* image) { AutocompleteTextFieldCell* cell = [field autocompleteTextFieldCell]; const CGFloat availableWidth([field availableDecorationWidth]); @@ -305,6 +298,12 @@ void LocationBarViewMac::OnChangedImpl(AutocompleteTextField* field, [cell setKeywordHintPrefix:prefix image:image suffix:suffix availableWidth:availableWidth]; + } else if (show_search_hint) { + // Show a search hint right-justified in the field if there is no + // keyword. + const std::wstring hint(l10n_util::GetString(IDS_OMNIBOX_EMPTY_TEXT)); + [cell setSearchHintString:base::SysWideToNSString(hint) + availableWidth:availableWidth]; } else { // Nothing interesting to show, plain old text field. [cell clearKeywordAndHint]; @@ -331,6 +330,7 @@ void LocationBarViewMac::OnChanged() { keyword, short_name, edit_view_->model()->is_keyword_hint(), + edit_view_->model()->show_search_hint(), GetTabButtonImage()); } @@ -444,22 +444,6 @@ void LocationBarViewMac::TestPageActionPressed(size_t index) { page_action_views_.OnMousePressed(NSZeroRect, index); } -void LocationBarViewMac::SetEditable(bool editable) { - [field_ setEditable:editable ? YES : NO]; - star_icon_view_.SetVisible(editable); - UpdatePageActions(); -} - -bool LocationBarViewMac::IsEditable() { - return [field_ isEditable] ? true : false; -} - -void LocationBarViewMac::SetStarred(bool starred) { - star_icon_view_.SetStarred(starred); - [field_ updateCursorAndToolTipRects]; - [field_ resetFieldEditorFrameIfNeeded]; -} - NSImage* LocationBarViewMac::GetTabButtonImage() { if (!tab_button_image_) { SkBitmap* skiaBitmap = ResourceBundle::GetSharedInstance(). @@ -471,37 +455,44 @@ NSImage* LocationBarViewMac::GetTabButtonImage() { return tab_button_image_; } -void LocationBarViewMac::SetIcon(int resource_id) { - DCHECK(resource_id != 0); - - // The icon is always visible except when there is a keyword hint. - if (!edit_view_->model()->keyword().empty() && - !edit_view_->model()->is_keyword_hint()) { - location_icon_view_.SetVisible(false); +void LocationBarViewMac::SetSecurityIconLabel() { + std::wstring info_text; + std::wstring info_tooltip; + ToolbarModel::InfoTextType info_text_type = + toolbar_model_->GetInfoText(&info_text, &info_tooltip); + if (info_text_type == ToolbarModel::INFO_EV_TEXT) { + NSString* icon_label = base::SysWideToNSString(info_text); + NSColor* color = [NSColor colorWithCalibratedRed:kEvTextColorRedComponent + green:kEvTextColorGreenComponent + blue:kEvTextColorBlueComponent + alpha:1.0]; + security_image_view_.SetLabel(icon_label, [field_ font], color); } else { - NSImage* image = AutocompleteEditViewMac::ImageForResource(resource_id); - location_icon_view_.SetImage(image); - location_icon_view_.SetVisible(true); - SetSecurityLabel(); + security_image_view_.SetLabel(nil, nil, nil); } - [field_ resetFieldEditorFrameIfNeeded]; } -void LocationBarViewMac::SetSecurityLabel() { - if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) { - std::wstring security_info_text(toolbar_model_->GetEVCertName()); - NSString* icon_label = base::SysWideToNSString(security_info_text); - NSColor* color = - [NSColor colorWithCalibratedRed:kEVSecureTextColorRedComponent - green:kEVSecureTextColorGreenComponent - blue:kEVSecureTextColorBlueComponent - alpha:1.0]; - security_label_view_.SetLabel(icon_label, [field_ font], color); - security_label_view_.SetVisible(true); - } else { - security_label_view_.SetLabel(nil, nil, nil); - security_label_view_.SetVisible(false); +void LocationBarViewMac::SetSecurityIcon(ToolbarModel::Icon icon) { + switch (icon) { + case ToolbarModel::LOCK_ICON: + security_image_view_.SetImageShown(SecurityImageView::LOCK); + security_image_view_.SetVisible(true); + SetSecurityIconLabel(); + break; + case ToolbarModel::WARNING_ICON: + security_image_view_.SetImageShown(SecurityImageView::WARNING); + security_image_view_.SetVisible(true); + SetSecurityIconLabel(); + break; + case ToolbarModel::NO_ICON: + security_image_view_.SetVisible(false); + break; + default: + NOTREACHED(); + security_image_view_.SetVisible(false); + break; } + [field_ resetFieldEditorFrameIfNeeded]; } void LocationBarViewMac::Observe(NotificationType type, @@ -544,9 +535,8 @@ void LocationBarViewMac::LocationBarImageView::SetImage(NSImage* image) { image_.reset([image retain]); } -void LocationBarViewMac::LocationBarImageView::SetIcon(int resource_id) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - SetImage(rb.GetNSImageNamed(resource_id)); +void LocationBarViewMac::LocationBarImageView::SetImage(SkBitmap* image) { + SetImage(gfx::SkBitmapToNSImage(*image)); } void LocationBarViewMac::LocationBarImageView::SetLabel(NSString* text, @@ -574,32 +564,43 @@ void LocationBarViewMac::LocationBarImageView::SetVisible(bool visible) { visible_ = visible; } -NSSize LocationBarViewMac::LocationBarImageView::GetDefaultImageSize() const { - return NSZeroSize; -} +// SecurityImageView------------------------------------------------------------ -NSSize LocationBarViewMac::LocationBarImageView::GetImageSize() const { - NSImage* image = GetImage(); - if (image) - return [image size]; - return GetDefaultImageSize(); -} +LocationBarViewMac::SecurityImageView::SecurityImageView( + LocationBarViewMac* owner, + Profile* profile, + ToolbarModel* model) + : lock_icon_(nil), + warning_icon_(nil), + owner_(owner), + profile_(profile), + model_(model) {} -// LocationIconView ------------------------------------------------------------ +LocationBarViewMac::SecurityImageView::~SecurityImageView() {} -LocationBarViewMac::LocationIconView::LocationIconView( - LocationBarViewMac* owner) - : owner_(owner) { +void LocationBarViewMac::SecurityImageView::SetImageShown(Image image) { + switch (image) { + case LOCK: + if (!lock_icon_.get()) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + lock_icon_.reset([rb.GetNSImageNamed(IDR_LOCK) retain]); + } + SetImage(lock_icon_); + break; + case WARNING: + if (!warning_icon_.get()) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + warning_icon_.reset([rb.GetNSImageNamed(IDR_WARNING) retain]); + } + SetImage(warning_icon_); + break; + default: + NOTREACHED(); + break; + } } -LocationBarViewMac::LocationIconView::~LocationIconView() {} - -void LocationBarViewMac::LocationIconView::OnMousePressed(NSRect bounds) { - // Do not show page info if the user has been editing the location - // bar, or the location bar is at the NTP. - if (owner_->location_entry()->IsEditingOrEmpty()) - return; - +void LocationBarViewMac::SecurityImageView::OnMousePressed(NSRect bounds) { TabContents* tab = owner_->GetTabContents(); NavigationEntry* nav_entry = tab->controller().GetActiveEntry(); if (!nav_entry) { @@ -609,57 +610,6 @@ void LocationBarViewMac::LocationIconView::OnMousePressed(NSRect bounds) { tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true); } -bool LocationBarViewMac::LocationIconView::IsDraggable() { - // Do not drag if the user has been editing the location bar, or the - // location bar is at the NTP. - if (owner_->location_entry()->IsEditingOrEmpty()) - return false; - - return true; -} - -NSPasteboard* LocationBarViewMac::LocationIconView::GetDragPasteboard() { - TabContents* tab = owner_->GetTabContents(); - DCHECK(tab); - - NSString* url = base::SysUTF8ToNSString(tab->GetURL().spec()); - NSString* title = base::SysUTF16ToNSString(tab->GetTitle()); - - NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array] - owner:nil]; - [pboard setDataForURL:url title:title]; - return pboard; -} - -// StarIconView----------------------------------------------------------------- - -LocationBarViewMac::StarIconView::StarIconView(CommandUpdater* command_updater) - : command_updater_(command_updater) { - SetVisible(true); - SetStarred(false); -} - -void LocationBarViewMac::StarIconView::SetStarred(bool starred) { - if (starred) { - SetImage(AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_STAR_LIT)); - tooltip_.reset( - [l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STARRED) retain]); - } else { - SetImage(AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_STAR)); - tooltip_.reset( - [l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STAR) retain]); - } -} - -void LocationBarViewMac::StarIconView::OnMousePressed(NSRect bounds) { - command_updater_->ExecuteCommand(IDC_BOOKMARK_PAGE); -} - -const NSString* LocationBarViewMac::StarIconView::GetToolTip() { - return tooltip_.get(); -} - // PageActionImageView---------------------------------------------------------- LocationBarViewMac::PageActionImageView::PageActionImageView( @@ -697,9 +647,14 @@ LocationBarViewMac::PageActionImageView::PageActionImageView( LocationBarViewMac::PageActionImageView::~PageActionImageView() { } -NSSize LocationBarViewMac::PageActionImageView::GetDefaultImageSize() const { - return NSMakeSize(Extension::kPageActionIconMaxSize, - Extension::kPageActionIconMaxSize); +NSSize LocationBarViewMac::PageActionImageView::GetPreferredImageSize() { + NSImage* image = GetImage(); + if (image) { + return [image size]; + } else { + return NSMakeSize(Extension::kPageActionIconMaxSize, + Extension::kPageActionIconMaxSize); + } } // Overridden from LocationBarImageView. Either notify listeners or show a @@ -913,9 +868,10 @@ void LocationBarViewMac::ContentSettingImageView::UpdateFromTabContents( const TabContents* tab_contents) { content_setting_image_model_->UpdateFromTabContents(tab_contents); if (content_setting_image_model_->is_visible()) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); // TODO(thakis): We should use pdfs for these icons on OSX. // http://crbug.com/35847 - SetIcon(content_setting_image_model_->get_icon()); + SetImage(rb.GetNSImageNamed(content_setting_image_model_->get_icon())); SetToolTip(base::SysUTF8ToNSString( content_setting_image_model_->get_tooltip())); SetVisible(true); @@ -939,11 +895,6 @@ void LocationBarViewMac::PageActionViewList::DeleteAll() { } void LocationBarViewMac::PageActionViewList::RefreshViews() { - if (!owner_->IsEditable()) { - DeleteAll(); - return; - } - std::vector page_actions; ExtensionsService* service = profile_->GetExtensionsService(); if (!service) diff --git a/chrome/browser/cocoa/location_bar_view_mac_unittest.mm b/chrome/browser/cocoa/location_bar_view_mac_unittest.mm index ecb2a7b..aec948d 100644 --- a/chrome/browser/cocoa/location_bar_view_mac_unittest.mm +++ b/chrome/browser/cocoa/location_bar_view_mac_unittest.mm @@ -81,6 +81,7 @@ TEST_F(LocationBarViewMacTest, OnChangedImpl) { NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"]; const std::wstring kKeyword(L"Google"); + const NSString* kSearchHint = @"Type to search"; const NSString* kKeywordPrefix = @"Press "; const NSString* kKeywordSuffix = @" to search Google"; const NSString* kKeywordString = @"Search Google:"; @@ -89,20 +90,39 @@ TEST_F(LocationBarViewMacTest, OnChangedImpl) { [NSString stringWithFormat:@"Search Go%C:", 0x2026]; // With no special hints requested, none set. - LocationBarViewMac::OnChangedImpl(field_, std::wstring(), std::wstring(), false, image); + LocationBarViewMac::OnChangedImpl( + field_, std::wstring(), std::wstring(), false, false, image); EXPECT_FALSE([cell keywordString]); EXPECT_FALSE([cell hintString]); - // Request a keyword hint. - LocationBarViewMac::OnChangedImpl(field_, kKeyword, kKeyword, true, image); + // Request only a search hint. + LocationBarViewMac::OnChangedImpl( + field_, std::wstring(), std::wstring(), false, true, image); + EXPECT_FALSE([cell keywordString]); + EXPECT_TRUE([[[cell hintString] string] isEqualToString:kSearchHint]); + + // Request a keyword hint, same results whether |search_hint| + // parameter is true or false. + LocationBarViewMac::OnChangedImpl( + field_, kKeyword, kKeyword, true, true, image); + EXPECT_FALSE([cell keywordString]); + EXPECT_TRUE([[[cell hintString] string] hasPrefix:kKeywordPrefix]); + EXPECT_TRUE([[[cell hintString] string] hasSuffix:kKeywordSuffix]); + LocationBarViewMac::OnChangedImpl( + field_, kKeyword, kKeyword, true, false, image); EXPECT_FALSE([cell keywordString]); EXPECT_TRUE([[[cell hintString] string] hasPrefix:kKeywordPrefix]); EXPECT_TRUE([[[cell hintString] string] hasSuffix:kKeywordSuffix]); - // Request keyword-search mode. + // Request keyword-search mode, same results whether |search_hint| + // parameter is true or false. LocationBarViewMac::OnChangedImpl( - field_, kKeyword, kKeyword, false, image); - EXPECT_TRUE([[[cell keywordString] string] hasSuffix:kKeywordString]); + field_, kKeyword, kKeyword, false, true, image); + EXPECT_TRUE([[[cell keywordString] string] isEqualToString:kKeywordString]); + EXPECT_FALSE([cell hintString]); + LocationBarViewMac::OnChangedImpl( + field_, kKeyword, kKeyword, false, false, image); + EXPECT_TRUE([[[cell keywordString] string] isEqualToString:kKeywordString]); EXPECT_FALSE([cell hintString]); // Check that a partial keyword-search string is passed down in case @@ -112,13 +132,14 @@ TEST_F(LocationBarViewMacTest, OnChangedImpl) { NSRect frame([field_ frame]); frame.size.width = 10.0; [field_ setFrame:frame]; - LocationBarViewMac::OnChangedImpl(field_, kKeyword, kKeyword, false, image); + LocationBarViewMac::OnChangedImpl( + field_, kKeyword, kKeyword, false, true, image); EXPECT_TRUE([[[cell keywordString] string] isEqualToString:kPartialString]); EXPECT_FALSE([cell hintString]); // Transition back to baseline. LocationBarViewMac::OnChangedImpl( - field_, std::wstring(), std::wstring(), false, image); + field_, std::wstring(), std::wstring(), false, false, image); EXPECT_FALSE([cell keywordString]); EXPECT_FALSE([cell hintString]); } diff --git a/chrome/browser/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/cocoa/status_bubble_mac_unittest.mm index 6f4dab4..3dd628e 100644 --- a/chrome/browser/cocoa/status_bubble_mac_unittest.mm +++ b/chrome/browser/cocoa/status_bubble_mac_unittest.mm @@ -141,7 +141,7 @@ TEST_F(StatusBubbleMacTest, SetURL) { EXPECT_TRUE([GetURLText() isEqualToString:@"foopy://"]); bubble_->SetURL(GURL("http://www.cnn.com"), L""); EXPECT_TRUE(IsVisible()); - EXPECT_TRUE([GetURLText() isEqualToString:@"www.cnn.com/"]); + EXPECT_TRUE([GetURLText() isEqualToString:@"http://www.cnn.com/"]); } // Test hiding bubble that's already hidden. @@ -162,7 +162,7 @@ TEST_F(StatusBubbleMacTest, SetStatusAndURL) { EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"Status"]); bubble_->SetURL(GURL("http://www.nytimes.com/"), L""); EXPECT_TRUE(IsVisible()); - EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"www.nytimes.com/"]); + EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"http://www.nytimes.com/"]); bubble_->SetURL(GURL(), L""); EXPECT_TRUE(IsVisible()); EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"Status"]); @@ -170,13 +170,13 @@ TEST_F(StatusBubbleMacTest, SetStatusAndURL) { EXPECT_FALSE(IsVisible()); bubble_->SetURL(GURL("http://www.nytimes.com/"), L""); EXPECT_TRUE(IsVisible()); - EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"www.nytimes.com/"]); + EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"http://www.nytimes.com/"]); bubble_->SetStatus(L"Status"); EXPECT_TRUE(IsVisible()); EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"Status"]); bubble_->SetStatus(L""); EXPECT_TRUE(IsVisible()); - EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"www.nytimes.com/"]); + EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"http://www.nytimes.com/"]); bubble_->SetURL(GURL(), L""); EXPECT_FALSE(IsVisible()); } diff --git a/chrome/browser/cocoa/tab_strip_controller_unittest.mm b/chrome/browser/cocoa/tab_strip_controller_unittest.mm index 82cea8e..0967ae4 100644 --- a/chrome/browser/cocoa/tab_strip_controller_unittest.mm +++ b/chrome/browser/cocoa/tab_strip_controller_unittest.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h index c038077..3c5086b 100644 --- a/chrome/browser/cocoa/toolbar_controller.h +++ b/chrome/browser/cocoa/toolbar_controller.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -22,6 +22,7 @@ class AppMenuModel; @class BackForwardMenuController; class Browser; @class BrowserActionsController; +class BubblePositioner; class CommandUpdater; @class DelayedMenuButton; class LocationBar; @@ -69,6 +70,8 @@ class ToolbarModel; // Used for monitoring the optional toolbar button prefs. scoped_ptr prefObserver_; + // Used to position the omnibox bubble. + scoped_ptr bubblePositioner_; BooleanPrefMember showHomeButton_; BooleanPrefMember showPageOptionButtons_; BOOL hasToolbar_; // If NO, we may have only the location bar. @@ -96,6 +99,7 @@ class ToolbarModel; IBOutlet DelayedMenuButton* forwardButton_; IBOutlet NSButton* reloadButton_; IBOutlet NSButton* homeButton_; + IBOutlet NSButton* starButton_; IBOutlet NSButton* goButton_; IBOutlet MenuButton* pageButton_; IBOutlet MenuButton* wrenchButton_; @@ -143,10 +147,9 @@ class ToolbarModel; // ignored. This changes the behavior of other methods, like |-view|. - (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar; -// The bookmark bubble (when you click the star or hit Command-d) -// needs to know where to go. Somewhere near the star icon seems like -// a good start. -- (NSRect)starIconInWindowCoordinates; +// The bookmark bubble (when you click the star) needs to know where to go. +// Somewhere near the star button seems like a good start. +- (NSRect)starButtonInWindowCoordinates; // Returns the desired toolbar height for the given compression factor. - (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight; @@ -168,6 +171,7 @@ class ToolbarModel; - (NSArray*)toolbarViews; - (void)showOptionalHomeButton; - (void)showOptionalPageWrenchButtons; +- (gfx::Rect)locationStackBounds; // Return a hover button for the current event. - (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent; @end diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm index 085c493..0d12ee5 100644 --- a/chrome/browser/cocoa/toolbar_controller.mm +++ b/chrome/browser/cocoa/toolbar_controller.mm @@ -15,6 +15,7 @@ #include "chrome/browser/autocomplete/autocomplete_edit_view.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_window.h" +#include "chrome/browser/bubble_positioner.h" #import "chrome/browser/cocoa/autocomplete_text_field.h" #import "chrome/browser/cocoa/autocomplete_text_field_editor.h" #import "chrome/browser/cocoa/back_forward_menu_controller.h" @@ -50,6 +51,8 @@ NSString* const kBackButtonImageName = @"back_Template.pdf"; NSString* const kForwardButtonImageName = @"forward_Template.pdf"; NSString* const kReloadButtonImageName = @"reload_Template.pdf"; NSString* const kHomeButtonImageName = @"home_Template.pdf"; +NSString* const kStarButtonImageName = @"star_Template.pdf"; +NSString* const kStarButtonFillingImageName = @"starred.pdf"; NSString* const kGoButtonGoImageName = @"go_Template.pdf"; NSString* const kGoButtonStopImageName = @"stop_Template.pdf"; NSString* const kPageButtonImageName = @"menu_page_Template.pdf"; @@ -84,6 +87,26 @@ const CGFloat kAnimationDuration = 0.2; - (void)adjustLocationAndGoPositionsBy:(CGFloat)dX animate:(BOOL)animate; @end +namespace { + +// A C++ class used to correctly position the omnibox. +class BubblePositionerMac : public BubblePositioner { + public: + BubblePositionerMac(ToolbarController* controller) + : controller_(controller) { } + virtual ~BubblePositionerMac() { } + + // BubblePositioner: + virtual gfx::Rect GetLocationStackBounds() const { + return [controller_ locationStackBounds]; + } + + private: + ToolbarController* controller_; // weak, owns us +}; + +} // namespace + namespace ToolbarControllerInternal { // A C++ delegate that handles enabling/disabling menu items and handling when @@ -202,6 +225,7 @@ class PrefObserverBridge : public NotificationObserver { [forwardButton_ setImage:nsimage_cache::ImageNamed(kForwardButtonImageName)]; [reloadButton_ setImage:nsimage_cache::ImageNamed(kReloadButtonImageName)]; [homeButton_ setImage:nsimage_cache::ImageNamed(kHomeButtonImageName)]; + [starButton_ setImage:nsimage_cache::ImageNamed(kStarButtonImageName)]; [goButton_ setImage:nsimage_cache::ImageNamed(kGoButtonGoImageName)]; [pageButton_ setImage:nsimage_cache::ImageNamed(kPageButtonImageName)]; [wrenchButton_ setImage:nsimage_cache::ImageNamed(kWrenchButtonImageName)]; @@ -210,7 +234,9 @@ class PrefObserverBridge : public NotificationObserver { [wrenchButton_ setShowsBorderOnlyWhileMouseInside:YES]; [self initCommandStatus:commands_]; + bubblePositioner_.reset(new BubblePositionerMac(self)); locationBarView_.reset(new LocationBarViewMac(locationBar_, + bubblePositioner_.get(), commands_, toolbarModel_, profile_, browser_)); [locationBar_ setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; @@ -286,6 +312,10 @@ class PrefObserverBridge : public NotificationObserver { [[homeButton_ cell] accessibilitySetOverrideValue:description forAttribute:NSAccessibilityDescriptionAttribute]; + description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_STAR); + [[starButton_ cell] + accessibilitySetOverrideValue:description + forAttribute:NSAccessibilityDescriptionAttribute]; description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_LOCATION); [[locationBar_ cell] accessibilitySetOverrideValue:description @@ -364,6 +394,9 @@ class PrefObserverBridge : public NotificationObserver { case IDC_HOME: button = homeButton_; break; + case IDC_BOOKMARK_PAGE: + button = starButton_; + break; } [button setEnabled:enabled]; } @@ -376,6 +409,8 @@ class PrefObserverBridge : public NotificationObserver { setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO]; [reloadButton_ setEnabled:commands->IsCommandEnabled(IDC_RELOAD) ? YES : NO]; [homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO]; + [starButton_ + setEnabled:commands->IsCommandEnabled(IDC_BOOKMARK_PAGE) ? YES : NO]; } - (void)updateToolbarWithContents:(TabContents*)tab @@ -390,7 +425,23 @@ class PrefObserverBridge : public NotificationObserver { } - (void)setStarredState:(BOOL)isStarred { - locationBarView_->SetStarred(isStarred ? true : false); + NSImage* starImage = nil; + NSString* toolTip; + if (isStarred) { + starImage = nsimage_cache::ImageNamed(kStarButtonFillingImageName); + // Cache the string since we'll need it a lot + static NSString* starredToolTip = + [l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STARRED) retain]; + toolTip = starredToolTip; + } else { + // Cache the string since we'll need it a lot + static NSString* starToolTip = + [l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STAR) retain]; + toolTip = starToolTip; + } + + [(GradientButtonCell*)[starButton_ cell] setUnderlayImage:starImage]; + [starButton_ setToolTip:toolTip]; } - (void)setIsLoading:(BOOL)isLoading { @@ -419,7 +470,7 @@ class PrefObserverBridge : public NotificationObserver { // Make location bar not editable when in a pop-up. // TODO(viettrungluu): is this right (all the time)? - locationBarView_->SetEditable(toolbar ? true : false); + [locationBar_ setEditable:toolbar]; } - (NSView*)view { @@ -457,7 +508,7 @@ class PrefObserverBridge : public NotificationObserver { // Returns an array of views in the order of the outlets above. - (NSArray*)toolbarViews { return [NSArray arrayWithObjects:backButton_, forwardButton_, reloadButton_, - homeButton_, goButton_, pageButton_, wrenchButton_, + homeButton_, starButton_, goButton_, pageButton_, wrenchButton_, locationBar_, browserActionsContainerView_, nil]; } @@ -470,16 +521,14 @@ class PrefObserverBridge : public NotificationObserver { return frame; } -// Computes the padding between the buttons that should have a -// separation from the positions in the nib. |homeButton_| is right -// of |forwardButton_| unless it has been hidden, in which case -// |reloadButton_| is in that spot. +// Computes the padding between the buttons that should have a separation from +// the positions in the nib. Since the forward and reload buttons are always +// visible, we use those buttons as the canonical spacing. - (CGFloat)interButtonSpacing { - const NSRect forwardFrame = [forwardButton_ frame]; - NSButton* nextButton = [homeButton_ isHidden] ? reloadButton_ : homeButton_; - const NSRect nextButtonFrame = [nextButton frame]; - DCHECK_GT(NSMinX(nextButtonFrame), NSMaxX(forwardFrame)); - return NSMinX(nextButtonFrame) - NSMaxX(forwardFrame); + NSRect forwardFrame = [forwardButton_ frame]; + NSRect reloadFrame = [reloadButton_ frame]; + DCHECK(NSMinX(reloadFrame) > NSMaxX(forwardFrame)); + return NSMinX(reloadFrame) - NSMaxX(forwardFrame); } // Show or hide the home button based on the pref. @@ -498,7 +547,7 @@ class PrefObserverBridge : public NotificationObserver { if (hide) moveX *= -1; // Reverse the direction of the move. - [reloadButton_ setFrame:NSOffsetRect([reloadButton_ frame], moveX, 0)]; + [starButton_ setFrame:NSOffsetRect([starButton_ frame], moveX, 0)]; [locationBar_ setFrame:[self adjustRect:[locationBar_ frame] byAmount:moveX]]; [homeButton_ setHidden:hide]; @@ -721,8 +770,8 @@ class PrefObserverBridge : public NotificationObserver { [NSAnimationContext endGrouping]; } -- (NSRect)starIconInWindowCoordinates { - return [locationBar_ convertRect:[locationBar_ starIconFrame] toView:nil]; +- (NSRect)starButtonInWindowCoordinates { + return [starButton_ convertRect:[starButton_ bounds] toView:nil]; } - (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight { @@ -797,6 +846,31 @@ class PrefObserverBridge : public NotificationObserver { } +- (gfx::Rect)locationStackBounds { + // The number of pixels from the left or right edges of the location stack to + // "just inside the visible borders". When the omnibox bubble contents are + // aligned with this, the visible borders tacked on to the outsides will line + // up with the visible borders on the location stack. + const int kLocationStackEdgeWidth = 2; + + const NSRect locationFrame = [locationBar_ frame]; + + // Expand to include star and go buttons. Including the widths + // rather that calculating from their current placement because this + // method can be called while the resize is still rearranging the + // views involved. + const CGFloat minX = NSMinX(locationFrame) - NSWidth([starButton_ frame]); + const CGFloat maxX = NSMaxX(locationFrame) + NSWidth([goButton_ frame]); + + NSRect r = NSMakeRect(minX, NSMinY(locationFrame), maxX - minX, + NSHeight(locationFrame)); + gfx::Rect stack_bounds( + NSRectToCGRect([[self view] convertRect:r toView:nil])); + // Inset the bounds to just inside the visible edges (see comment above). + stack_bounds.Inset(kLocationStackEdgeWidth, 0); + return stack_bounds; +} + // (URLDropTargetController protocol) - (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point { // TODO(viettrungluu): This code is more or less copied from the code in diff --git a/chrome/browser/cocoa/toolbar_controller_unittest.mm b/chrome/browser/cocoa/toolbar_controller_unittest.mm index 08e3176..dab5cba 100644 --- a/chrome/browser/cocoa/toolbar_controller_unittest.mm +++ b/chrome/browser/cocoa/toolbar_controller_unittest.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -43,7 +43,7 @@ class ToolbarControllerTest : public CocoaTest { // Indexes that match the ordering returned by the private ToolbarController // |-toolbarViews| method. enum { - kBackIndex, kForwardIndex, kReloadIndex, kHomeIndex, kGoIndex, + kBackIndex, kForwardIndex, kReloadIndex, kHomeIndex, kStarIndex, kGoIndex, kPageIndex, kWrenchIndex, kLocationIndex, kBrowserActionContainerViewIndex }; @@ -78,6 +78,8 @@ class ToolbarControllerTest : public CocoaTest { [[views objectAtIndex:kReloadIndex] isEnabled] ? true : false); EXPECT_EQ(updater->IsCommandEnabled(IDC_HOME), [[views objectAtIndex:kHomeIndex] isEnabled] ? true : false); + EXPECT_EQ(updater->IsCommandEnabled(IDC_BOOKMARK_PAGE), + [[views objectAtIndex:kStarIndex] isEnabled] ? true : false); } BrowserTestHelper helper_; @@ -158,16 +160,16 @@ TEST_F(ToolbarControllerTest, ToggleHome) { NSView* homeButton = [[bar_ toolbarViews] objectAtIndex:kHomeIndex]; EXPECT_EQ(showHome, ![homeButton isHidden]); - NSView* reloadButton = [[bar_ toolbarViews] objectAtIndex:kReloadIndex]; + NSView* starButton = [[bar_ toolbarViews] objectAtIndex:kStarIndex]; NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex]; - NSRect originalReloadFrame = [reloadButton frame]; + NSRect originalStarFrame = [starButton frame]; NSRect originalLocationBarFrame = [locationBar frame]; // Toggle the pref and make sure the button changed state and the other // views moved. prefs->SetBoolean(prefs::kShowHomeButton, !showHome); EXPECT_EQ(showHome, [homeButton isHidden]); - EXPECT_NE(NSMinX(originalReloadFrame), NSMinX([reloadButton frame])); + EXPECT_NE(NSMinX(originalStarFrame), NSMinX([starButton frame])); EXPECT_NE(NSMinX(originalLocationBarFrame), NSMinX([locationBar frame])); EXPECT_NE(NSWidth(originalLocationBarFrame), NSWidth([locationBar frame])); } @@ -218,14 +220,32 @@ TEST_F(ToolbarControllerTest, DontToggleWhenNoToolbar) { EXPECT_TRUE(NSEqualRects(locationBarFrame, newLocationBarFrame)); } -TEST_F(ToolbarControllerTest, StarIconInWindowCoordinates) { - NSRect star = [bar_ starIconInWindowCoordinates]; +TEST_F(ToolbarControllerTest, StarButtonInWindowCoordinates) { + NSRect star = [bar_ starButtonInWindowCoordinates]; NSRect all = [[[bar_ view] window] frame]; // Make sure the star is completely inside the window rect EXPECT_TRUE(NSContainsRect(all, star)); } +TEST_F(ToolbarControllerTest, BubblePosition) { + NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex]; + + // The window frame (in window base coordinates). + NSRect all = [[[bar_ view] window] frame]; + // The frame of the location bar in window base coordinates. + NSRect locationFrame = + [locationBar convertRect:[locationBar bounds] toView:nil]; + // The frame of the location stack in window base coordinates. The horizontal + // coordinates here are used for the omnibox dropdown. + gfx::Rect locationStackFrame = [bar_ locationStackBounds]; + + // Make sure the location stack starts to the left of and ends to the right of + // the location bar. + EXPECT_LT(locationStackFrame.x(), NSMinX(locationFrame)); + EXPECT_GT(locationStackFrame.right(), NSMaxX(locationFrame)); +} + TEST_F(ToolbarControllerTest, HoverButtonForEvent) { scoped_nsobject view([[HitView alloc] initWithFrame:NSMakeRect(0,0,100,100)]); diff --git a/chrome/browser/gtk/accelerators_gtk.cc b/chrome/browser/gtk/accelerators_gtk.cc index c93d8f0..21ffe03 100644 --- a/chrome/browser/gtk/accelerators_gtk.cc +++ b/chrome/browser/gtk/accelerators_gtk.cc @@ -151,7 +151,8 @@ const struct AcceleratorMapping { { GDK_o, IDC_OPEN_FILE, GDK_CONTROL_MASK }, { GDK_f, IDC_FIND, GDK_CONTROL_MASK }, { GDK_p, IDC_PRINT, GDK_CONTROL_MASK }, - { GDK_b, IDC_SHOW_BOOKMARK_BAR, + { GDK_b, IDC_SHOW_BOOKMARK_BAR, GDK_CONTROL_MASK }, + { GDK_b, IDC_SHOW_BOOKMARK_MANAGER, GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) }, { GDK_F11, IDC_FULLSCREEN, GdkModifierType(0) }, { GDK_Delete, IDC_CLEAR_BROWSING_DATA, diff --git a/chrome/browser/gtk/bookmark_bubble_gtk.cc b/chrome/browser/gtk/bookmark_bubble_gtk.cc index 2bf86e2..524c9c3 100644 --- a/chrome/browser/gtk/bookmark_bubble_gtk.cc +++ b/chrome/browser/gtk/bookmark_bubble_gtk.cc @@ -219,7 +219,7 @@ BookmarkBubbleGtk::BookmarkBubbleGtk(GtkWidget* anchor, gtk_container_set_focus_child(GTK_CONTAINER(content), table); InfoBubbleGtk::ArrowLocationGtk arrow_location = - base::i18n::IsRTL() ? + !base::i18n::IsRTL() ? InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT : InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT; bubble_ = InfoBubbleGtk::Show(anchor_, diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc index bfe25fc..a4e79b0 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.cc +++ b/chrome/browser/gtk/browser_toolbar_gtk.cc @@ -35,6 +35,7 @@ #include "chrome/browser/gtk/location_bar_view_gtk.h" #include "chrome/browser/gtk/standard_menus.h" #include "chrome/browser/gtk/tabs/tab_strip_gtk.h" +#include "chrome/browser/gtk/toolbar_star_toggle_gtk.h" #include "chrome/browser/gtk/view_id_util.h" #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/pref_service.h" @@ -65,13 +66,17 @@ const int kToolbarHeightLocationBarOnly = kToolbarHeight - 2; // Interior spacing between toolbar widgets. const int kToolbarWidgetSpacing = 2; +// The color used as the base[] color of the location entry during a secure +// connection. +const GdkColor kSecureColor = GDK_COLOR_RGB(255, 245, 195); + } // namespace // BrowserToolbarGtk, public --------------------------------------------------- BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser, BrowserWindowGtk* window) : toolbar_(NULL), - location_bar_(new LocationBarViewGtk(browser)), + location_bar_(new LocationBarViewGtk(this, browser)), model_(browser->toolbar_model()), page_menu_model_(this, browser), app_menu_model_(this, browser), @@ -155,6 +160,11 @@ void BrowserToolbarGtk::Init(Profile* profile, gtk_box_pack_start(GTK_BOX(toolbar_), back_forward_hbox_, FALSE, FALSE, kToolbarWidgetSpacing); + reload_.reset(BuildToolbarButton(IDR_RELOAD, IDR_RELOAD_P, IDR_RELOAD_H, 0, + IDR_BUTTON_MASK, + l10n_util::GetStringUTF8(IDS_TOOLTIP_RELOAD), + GTK_STOCK_REFRESH)); + home_.reset(BuildToolbarButton(IDR_HOME, IDR_HOME_P, IDR_HOME_H, 0, IDR_BUTTON_MASK, l10n_util::GetStringUTF8(IDS_TOOLTIP_HOME), @@ -162,25 +172,23 @@ void BrowserToolbarGtk::Init(Profile* profile, gtk_util::SetButtonTriggersNavigation(home_->widget()); SetUpDragForHomeButton(); + // Group the start, omnibox, and go button into an hbox. + GtkWidget* location_hbox = gtk_hbox_new(FALSE, 0); + star_.reset(BuildStarButton(l10n_util::GetStringUTF8(IDS_TOOLTIP_STAR))); + gtk_box_pack_start(GTK_BOX(location_hbox), star_->widget(), FALSE, FALSE, 0); - reload_.reset(BuildToolbarButton(IDR_RELOAD, IDR_RELOAD_P, IDR_RELOAD_H, 0, - IDR_RELOAD_MASK, - l10n_util::GetStringUTF8(IDS_TOOLTIP_RELOAD), - GTK_STOCK_REFRESH)); - - location_hbox_ = gtk_hbox_new(FALSE, 0); location_bar_->Init(ShouldOnlyShowLocation()); - gtk_box_pack_start(GTK_BOX(location_hbox_), location_bar_->widget(), TRUE, + gtk_box_pack_start(GTK_BOX(location_hbox), location_bar_->widget(), TRUE, TRUE, 0); - g_signal_connect(location_hbox_, "expose-event", + go_.reset(new GoButtonGtk(location_bar_.get(), browser_)); + gtk_box_pack_start(GTK_BOX(location_hbox), go_->widget(), FALSE, FALSE, 0); + + g_signal_connect(location_hbox, "expose-event", G_CALLBACK(OnLocationHboxExposeThunk), this); - gtk_box_pack_start(GTK_BOX(toolbar_), location_hbox_, TRUE, TRUE, + gtk_box_pack_start(GTK_BOX(toolbar_), location_hbox, TRUE, TRUE, kToolbarWidgetSpacing + (ShouldOnlyShowLocation() ? 1 : 0)); - go_.reset(new GoButtonGtk(location_bar_.get(), browser_)); - gtk_box_pack_start(GTK_BOX(toolbar_), go_->widget(), FALSE, FALSE, 0); - if (!ShouldOnlyShowLocation()) { actions_toolbar_.reset(new BrowserActionsToolbarGtk(browser_)); gtk_box_pack_start(GTK_BOX(toolbar_), actions_toolbar_->widget(), @@ -219,16 +227,17 @@ void BrowserToolbarGtk::Init(Profile* profile, gtk_widget_show(event_box_); gtk_widget_show(alignment_); gtk_widget_show(toolbar_); - gtk_widget_show_all(location_hbox_); - gtk_widget_hide(reload_->widget()); + gtk_widget_show_all(location_hbox); + gtk_widget_hide(star_->widget()); gtk_widget_hide(go_->widget()); } else { gtk_widget_show_all(event_box_); - if (show_home_button_.GetValue()) + if (show_home_button_.GetValue()) { gtk_widget_show(home_->widget()); - else + } else { gtk_widget_hide(home_->widget()); + } if (actions_toolbar_->button_count() == 0) gtk_widget_hide(actions_toolbar_->widget()); @@ -239,7 +248,6 @@ void BrowserToolbarGtk::Init(Profile* profile, location_bar_->UpdateContentSettingsIcons(); SetViewIDs(); - theme_provider_->InitThemesFor(this); } void BrowserToolbarGtk::SetViewIDs() { @@ -248,6 +256,7 @@ void BrowserToolbarGtk::SetViewIDs() { ViewIDUtil::SetID(forward_->widget(), VIEW_ID_FORWARD_BUTTON); ViewIDUtil::SetID(reload_->widget(), VIEW_ID_RELOAD_BUTTON); ViewIDUtil::SetID(home_->widget(), VIEW_ID_HOME_BUTTON); + ViewIDUtil::SetID(star_->widget(), VIEW_ID_STAR_BUTTON); ViewIDUtil::SetID(location_bar_->widget(), VIEW_ID_LOCATION_BAR); ViewIDUtil::SetID(go_->widget(), VIEW_ID_GO_BUTTON); ViewIDUtil::SetID(page_menu_button_.get(), VIEW_ID_PAGE_MENU); @@ -303,6 +312,9 @@ void BrowserToolbarGtk::EnabledStateChangedForCommand(int id, bool enabled) { if (home_.get()) widget = home_->widget(); break; + case IDC_BOOKMARK_PAGE: + widget = star_->widget(); + break; } if (widget) { if (!enabled && GTK_WIDGET_STATE(widget) == GTK_STATE_PRELIGHT) { @@ -398,19 +410,6 @@ void BrowserToolbarGtk::Observe(NotificationType type, gtk_image_set_from_pixbuf(GTK_IMAGE(app_menu_image_), theme_provider_->GetRTLEnabledPixbufNamed(IDR_MENU_CHROME)); - // Update the spacing between the reload button and the location bar. - gtk_box_set_child_packing( - GTK_BOX(toolbar_), reload_->widget(), - FALSE, FALSE, - theme_provider_->UseGtkTheme() ? kToolbarWidgetSpacing : 0, - GTK_PACK_START); - gtk_box_set_child_packing( - GTK_BOX(toolbar_), location_hbox_, - TRUE, TRUE, - (theme_provider_->UseGtkTheme() ? kToolbarWidgetSpacing : 0) + - (ShouldOnlyShowLocation() ? 1 : 0), - GTK_PACK_START); - // When using the GTK+ theme, we need to have the event box be visible so // buttons don't get a halo color from the background. When using Chromium // themes, we want to let the background show through the toolbar. @@ -446,6 +445,38 @@ void BrowserToolbarGtk::UpdateTabContents(TabContents* contents, actions_toolbar_->Update(); } +gfx::Rect BrowserToolbarGtk::GetLocationStackBounds() const { + // The number of pixels from the left or right edges of the location stack to + // "just inside the visible borders". When the omnibox bubble contents are + // aligned with this, the visible borders tacked on to the outsides will line + // up with the visible borders on the location stack. + const int kLocationStackEdgeWidth = 1; + + GtkWidget* left; + GtkWidget* right; + if (base::i18n::IsRTL()) { + left = go_->widget(); + right = star_->widget(); + } else { + left = star_->widget(); + right = go_->widget(); + } + + gint origin_x, origin_y; + DCHECK_EQ(left->window, right->window); + gdk_window_get_origin(left->window, &origin_x, &origin_y); + + gint right_x = origin_x + right->allocation.x + right->allocation.width; + gint left_x = origin_x + left->allocation.x; + DCHECK_LE(left_x, right_x); + + gfx::Rect stack_bounds(left_x, origin_y + left->allocation.y, + right_x - left_x, left->allocation.height); + // Inset the bounds to just inside the visible edges (see comment above). + stack_bounds.Inset(kLocationStackEdgeWidth, 0); + return stack_bounds; +} + // BrowserToolbarGtk, private -------------------------------------------------- CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton( @@ -467,6 +498,18 @@ CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton( return button; } +ToolbarStarToggleGtk* BrowserToolbarGtk::BuildStarButton( + const std::string& localized_tooltip) { + ToolbarStarToggleGtk* button = new ToolbarStarToggleGtk(this); + + gtk_widget_set_tooltip_text(button->widget(), + localized_tooltip.c_str()); + g_signal_connect(button->widget(), "clicked", + G_CALLBACK(OnButtonClickThunk), this); + + return button; +} + GtkWidget* BrowserToolbarGtk::BuildToolbarMenuButton( const std::string& localized_tooltip, OwnedWidgetGtk* owner) { @@ -536,9 +579,42 @@ gboolean BrowserToolbarGtk::OnAlignmentExpose(GtkWidget* widget, gboolean BrowserToolbarGtk::OnLocationHboxExpose(GtkWidget* location_hbox, GdkEventExpose* e) { if (theme_provider_->UseGtkTheme()) { + // To get the proper look surrounding the location bar, we issue raw gtk + // painting commands to the theme engine. We figure out the region from the + // leftmost widget to the rightmost and then tell GTK to perform the same + // drawing commands that draw a GtkEntry on that region. + GtkWidget* star = star_->widget(); + GtkWidget* left = NULL; + GtkWidget* right = NULL; + if (ShouldOnlyShowLocation()) { + left = location_hbox; + right = location_hbox; + } else if (gtk_widget_get_direction(star) == GTK_TEXT_DIR_LTR) { + left = star_->widget(); + right = go_->widget(); + } else { + left = go_->widget(); + right = star_->widget(); + } + + GdkRectangle rec = { + left->allocation.x, + left->allocation.y, + (right->allocation.x - left->allocation.x) + right->allocation.width, + (right->allocation.y - left->allocation.y) + right->allocation.height + }; + + // Make sure our off screen entry has the correct base color if we're in + // secure mode. + gtk_widget_modify_base( + offscreen_entry_.get(), GTK_STATE_NORMAL, + (browser_->toolbar_model()->GetSchemeSecurityLevel() == + ToolbarModel::SECURE) ? + &kSecureColor : NULL); + gtk_util::DrawTextEntryBackground(offscreen_entry_.get(), location_hbox, &e->area, - &location_hbox->allocation); + &rec); } return FALSE; @@ -563,6 +639,8 @@ void BrowserToolbarGtk::OnButtonClick(GtkWidget* button) { location_bar_->Revert(); } else if (home_.get() && button == home_->widget()) { tag = IDC_HOME; + } else if (button == star_->widget()) { + tag = IDC_BOOKMARK_PAGE; } DCHECK_NE(tag, -1) << "Unexpected button click callback"; diff --git a/chrome/browser/gtk/browser_toolbar_gtk.h b/chrome/browser/gtk/browser_toolbar_gtk.h index 9c5f2c8..1ece0db 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.h +++ b/chrome/browser/gtk/browser_toolbar_gtk.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,8 +12,8 @@ #include "app/menus/simple_menu_model.h" #include "base/scoped_ptr.h" #include "chrome/browser/app_menu_model.h" +#include "chrome/browser/bubble_positioner.h" #include "chrome/browser/command_updater.h" -#include "chrome/browser/gtk/custom_button.h" #include "chrome/browser/gtk/menu_bar_helper.h" #include "chrome/browser/gtk/menu_gtk.h" #include "chrome/browser/page_menu_model.h" @@ -35,6 +35,7 @@ class LocationBarViewGtk; class Profile; class TabContents; class ToolbarModel; +class ToolbarStarToggleGtk; // View class that displays the GTK version of the toolbar and routes gtk // events back to the Browser. @@ -43,6 +44,7 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, public menus::SimpleMenuModel::Delegate, public MenuGtk::Delegate, public NotificationObserver, + public BubblePositioner, public MenuBarHelper::Delegate { public: explicit BrowserToolbarGtk(Browser* browser, BrowserWindowGtk* window); @@ -111,6 +113,11 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, // Message that we should react to a state change. void UpdateTabContents(TabContents* contents, bool should_restore_state); + ToolbarStarToggleGtk* star() { return star_.get(); } + + // BubblePositioner: + virtual gfx::Rect GetLocationStackBounds() const; + // MenuBarHelper::Delegate implementation ------------------------------------ virtual void PopupForButton(GtkWidget* button); virtual void PopupForButtonNextTo(GtkWidget* button, @@ -128,6 +135,9 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, const std::string& localized_tooltip, const char* stock_id); + // Create the star button given the tooltip. Returns the widget created. + ToolbarStarToggleGtk* BuildStarButton(const std::string& localized_tooltip); + // Create a menu for the toolbar given the icon id and tooltip. Returns the // widget created. GtkWidget* BuildToolbarMenuButton(const std::string& localized_tooltip, @@ -181,16 +191,14 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, // toolbar placed side by side. GtkWidget* toolbar_; - // Contains all the widgets of the location bar. - GtkWidget* location_hbox_; - // The location bar view. scoped_ptr location_bar_; // All the buttons in the toolbar. scoped_ptr back_, forward_; - scoped_ptr home_; scoped_ptr reload_; + scoped_ptr home_; + scoped_ptr star_; scoped_ptr go_; scoped_ptr actions_toolbar_; OwnedWidgetGtk page_menu_button_, app_menu_button_; diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index e31d564..03f9228 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -57,7 +57,6 @@ #include "chrome/browser/gtk/info_bubble_gtk.h" #include "chrome/browser/gtk/infobar_container_gtk.h" #include "chrome/browser/gtk/keyword_editor_view.h" -#include "chrome/browser/gtk/location_bar_view_gtk.h" #include "chrome/browser/gtk/nine_box.h" #include "chrome/browser/gtk/options/content_settings_window_gtk.h" #include "chrome/browser/gtk/repost_form_warning_gtk.h" @@ -66,6 +65,7 @@ #include "chrome/browser/gtk/tabs/tab_strip_gtk.h" #include "chrome/browser/gtk/task_manager_gtk.h" #include "chrome/browser/gtk/theme_install_bubble_view_gtk.h" +#include "chrome/browser/gtk/toolbar_star_toggle_gtk.h" #include "chrome/browser/location_bar.h" #include "chrome/browser/page_info_window.h" #include "chrome/browser/pref_service.h" @@ -742,7 +742,7 @@ void BrowserWindowGtk::LoadingAnimationCallback() { } void BrowserWindowGtk::SetStarredState(bool is_starred) { - toolbar_->GetLocationBarView()->SetStarred(is_starred); + toolbar_->star()->SetStarred(is_starred); } gfx::Rect BrowserWindowGtk::GetRestoredBounds() const { @@ -846,7 +846,7 @@ void BrowserWindowGtk::ShowBookmarkManager() { void BrowserWindowGtk::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) { - toolbar_->GetLocationBarView()->ShowStarBubble(url, !already_bookmarked); + toolbar_->star()->ShowStarBubble(url, !already_bookmarked); } bool BrowserWindowGtk::IsDownloadShelfVisible() const { diff --git a/chrome/browser/gtk/find_bar_gtk.cc b/chrome/browser/gtk/find_bar_gtk.cc index b8785da..e3bc7ff 100644 --- a/chrome/browser/gtk/find_bar_gtk.cc +++ b/chrome/browser/gtk/find_bar_gtk.cc @@ -456,7 +456,6 @@ void FindBarGtk::Observe(NotificationType type, container_height_ = -1; if (theme_provider_->UseGtkTheme()) { - gtk_widget_modify_cursor(text_entry_, NULL, NULL); gtk_widget_modify_base(text_entry_, GTK_STATE_NORMAL, NULL); gtk_widget_modify_text(text_entry_, GTK_STATE_NORMAL, NULL); @@ -483,7 +482,6 @@ void FindBarGtk::Observe(NotificationType type, gtk_misc_set_alignment(GTK_MISC(match_count_label_), 0.5, 0.5); } else { - gtk_widget_modify_cursor(text_entry_, &gfx::kGdkBlack, &gfx::kGdkGray); gtk_widget_modify_base(text_entry_, GTK_STATE_NORMAL, &kEntryBackgroundColor); gtk_widget_modify_text(text_entry_, GTK_STATE_NORMAL, diff --git a/chrome/browser/gtk/gtk_theme_provider.cc b/chrome/browser/gtk/gtk_theme_provider.cc index ab8cd00..651fdda 100644 --- a/chrome/browser/gtk/gtk_theme_provider.cc +++ b/chrome/browser/gtk/gtk_theme_provider.cc @@ -91,30 +91,10 @@ const int kThemeImages[] = { IDR_THEME_FRAME_INCOGNITO_INACTIVE, }; -// A list of icons used in the autocomplete view that should be tinted to the -// current gtk theme selection color so they stand out against the GtkEntry's -// base color. -const int kAutocompleteImages[] = { - IDR_OMNIBOX_HTTP, - IDR_OMNIBOX_HTTP_DARK, - IDR_OMNIBOX_HISTORY, - IDR_OMNIBOX_HISTORY_DARK, - IDR_OMNIBOX_SEARCH, - IDR_OMNIBOX_SEARCH_DARK, - IDR_OMNIBOX_MORE, - IDR_OMNIBOX_MORE_DARK, - IDR_OMNIBOX_STAR, - IDR_OMNIBOX_STAR_DARK, - IDR_GEOLOCATION_ALLOWED_LOCATIONBAR_ICON, - IDR_GEOLOCATION_DENIED_LOCATIONBAR_ICON -}; - bool IsOverridableImage(int id) { static std::set images; if (images.empty()) { images.insert(kThemeImages, kThemeImages + arraysize(kThemeImages)); - images.insert(kAutocompleteImages, - kAutocompleteImages + arraysize(kAutocompleteImages)); const std::set& buttons = BrowserThemeProvider::GetTintableToolbarButtons(); @@ -758,49 +738,15 @@ SkBitmap* GtkThemeProvider::GenerateGtkThemeBitmap(int id) const { return GenerateFrameImage( BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE); } - // Two sets of omnibox icons, the one for normal http and the one for - // history, include white backgrounds (and are supposed to, for the windows - // chrome-theme). On linux, where we have all sorts of wacky themes and - // color combinations we need to deal with, switch them out with - // transparent background versions. - case IDR_OMNIBOX_HTTP: { - TintMap::const_iterator it = tints_.find( - BrowserThemeProvider::TINT_BUTTONS); - DCHECK(it != tints_.end()); - return GenerateTintedIcon(IDR_OMNIBOX_HTTP_TRANSPARENT, it->second); - } - case IDR_OMNIBOX_HISTORY: { - TintMap::const_iterator it = tints_.find( - BrowserThemeProvider::TINT_BUTTONS); - DCHECK(it != tints_.end()); - return GenerateTintedIcon(IDR_OMNIBOX_HISTORY_TRANSPARENT, it->second); - } - // In GTK mode, the dark versions of the omnibox icons only ever appear in - // the autocomplete popup and only against the current theme's GtkEntry - // base[GTK_STATE_SELECTED] color, so tint the icons so they won't collide - // with the selected color. - case IDR_OMNIBOX_HTTP_DARK: { - color_utils::HSL tint; - GetEntryForegroundHSL(&tint); - return GenerateTintedIcon(IDR_OMNIBOX_HTTP_DARK_TRANSPARENT, tint); - } - case IDR_OMNIBOX_HISTORY_DARK: { - color_utils::HSL tint; - GetEntryForegroundHSL(&tint); - return GenerateTintedIcon(IDR_OMNIBOX_HISTORY_DARK_TRANSPARENT, tint); - } - case IDR_OMNIBOX_SEARCH_DARK: - case IDR_OMNIBOX_MORE_DARK: - case IDR_OMNIBOX_STAR_DARK: { - color_utils::HSL tint; - GetEntryForegroundHSL(&tint); - return GenerateTintedIcon(id, tint); - } default: { + // This is a tinted button. Tint it and return it. + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + scoped_ptr button(new SkBitmap(*rb.GetBitmapNamed(id))); TintMap::const_iterator it = tints_.find( BrowserThemeProvider::TINT_BUTTONS); DCHECK(it != tints_.end()); - return GenerateTintedIcon(id, it->second); + return new SkBitmap(SkBitmapOperations::CreateHSLShiftedBitmap( + *button, it->second)); } } } @@ -822,20 +768,6 @@ SkBitmap* GtkThemeProvider::GenerateTabImage(int base_id) const { bg_tint, 0, 0, bg_tint.width(), bg_tint.height())); } -SkBitmap* GtkThemeProvider::GenerateTintedIcon(int base_id, - color_utils::HSL tint) const { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - scoped_ptr button(new SkBitmap(*rb.GetBitmapNamed(base_id))); - return new SkBitmap(SkBitmapOperations::CreateHSLShiftedBitmap( - *button, tint)); -} - -void GtkThemeProvider::GetEntryForegroundHSL(color_utils::HSL* tint) const { - GtkStyle* style = gtk_rc_get_style(fake_entry_.get()); - const GdkColor color = style->text[GTK_STATE_SELECTED]; - color_utils::SkColorToHSL(GdkToSkColor(&color), tint); -} - void GtkThemeProvider::OnDestroyChromeButton(GtkWidget* button) { std::vector::iterator it = find(chrome_buttons_.begin(), chrome_buttons_.end(), button); diff --git a/chrome/browser/gtk/gtk_theme_provider.h b/chrome/browser/gtk/gtk_theme_provider.h index 227bbbe..23c0a57 100644 --- a/chrome/browser/gtk/gtk_theme_provider.h +++ b/chrome/browser/gtk/gtk_theme_provider.h @@ -163,13 +163,6 @@ class GtkThemeProvider : public BrowserThemeProvider, // Takes the base frame image |base_id| and tints it with |tint_id|. SkBitmap* GenerateTabImage(int base_id) const; - // Tints an icon based on tint. - SkBitmap* GenerateTintedIcon(int base_id, color_utils::HSL tint) const; - - // Returns a tint that's the color of the current highlighted text in an - // entry. - void GetEntryForegroundHSL(color_utils::HSL* tint) const; - // A notification from the GtkChromeButton GObject destructor that we should // remove it from our internal list. CHROMEGTK_CALLBACK_0(GtkThemeProvider, void, OnDestroyChromeButton); diff --git a/chrome/browser/gtk/gtk_util.cc b/chrome/browser/gtk/gtk_util.cc index 4d5796a..3013b12 100644 --- a/chrome/browser/gtk/gtk_util.cc +++ b/chrome/browser/gtk/gtk_util.cc @@ -17,13 +17,11 @@ #include "base/i18n/rtl.h" #include "base/linux_util.h" #include "base/logging.h" -#include "chrome/browser/autocomplete/autocomplete.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/gtk/cairo_cached_surface.h" #include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/common/renderer_preferences.h" -#include "googleurl/src/gurl.h" #include "grit/theme_resources.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" @@ -871,32 +869,4 @@ guint32 XTimeNow() { return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; } -bool URLFromPrimarySelection(Profile* profile, GURL* url) { - GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); - DCHECK(clipboard); - gchar* selection_text = gtk_clipboard_wait_for_text(clipboard); - if (!selection_text) - return false; - - // Use autocomplete to clean up the text, going so far as to turn it into - // a search query if necessary. - AutocompleteController controller(profile); - controller.Start(UTF8ToWide(selection_text), - std::wstring(), // desired_tld - true, // prevent_inline_autocomplete - false, // prefer_keyword - true); // synchronous_only - g_free(selection_text); - const AutocompleteResult& result = controller.result(); - AutocompleteResult::const_iterator it = result.default_match(); - if (it == result.end()) - return false; - - if (!it->destination_url.is_valid()) - return false; - - *url = it->destination_url; - return true; -} - } // namespace gtk_util diff --git a/chrome/browser/gtk/gtk_util.h b/chrome/browser/gtk/gtk_util.h index 1d8b6d3..e28778a 100644 --- a/chrome/browser/gtk/gtk_util.h +++ b/chrome/browser/gtk/gtk_util.h @@ -17,8 +17,6 @@ typedef struct _GtkWidget GtkWidget; class GtkThemeProvider; -class GURL; -class Profile; struct RendererPreferences; // from common/renderer_preferences.h namespace event_utils { @@ -272,11 +270,6 @@ void SetWMLastUserActionTime(GtkWindow* window); // function, instead using the timestamp from the latest GDK event. guint32 XTimeNow(); -// Uses the autocomplete controller for |profile| to convert the contents of the -// PRIMARY selection to a parsed URL. Returns true and sets |url| on success, -// otherwise returns false. -bool URLFromPrimarySelection(Profile* profile, GURL* url); - } // namespace gtk_util #endif // CHROME_BROWSER_GTK_GTK_UTIL_H_ diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc index 59da90c..453a8f54 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/gtk/location_bar_view_gtk.cc @@ -6,7 +6,6 @@ #include -#include "app/gtk_dnd_util.h" #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/basictypes.h" @@ -27,7 +26,6 @@ #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/gtk/bookmark_bubble_gtk.h" #include "chrome/browser/gtk/cairo_cached_surface.h" #include "chrome/browser/gtk/content_setting_bubble_gtk.h" #include "chrome/browser/gtk/extension_popup_gtk.h" @@ -35,7 +33,6 @@ #include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/browser/gtk/gtk_util.h" #include "chrome/browser/gtk/rounded_window.h" -#include "chrome/browser/gtk/view_id_util.h" #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/browser/search_engines/template_url_model.h" @@ -76,12 +73,10 @@ const int kHboxBorder = 4; // Padding between the elements in the bar. static const int kInnerPadding = 4; -// Colors used to draw the EV certificate rounded bubble. -const GdkColor kEvSecureTextColor = GDK_COLOR_RGB(0x07, 0x95, 0x00); -const GdkColor kEvSecureBackgroundColor = GDK_COLOR_RGB(0xef, 0xfc, 0xef); -const GdkColor kEvSecureBorderColor = GDK_COLOR_RGB(0x90, 0xc3, 0x90); - -// Colors used to draw the Tab to Search rounded bubble. +// TODO(deanm): Eventually this should be painted with the background png +// image, but for now we get pretty close by just drawing a solid border. +const GdkColor kBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4); +const GdkColor kEvTextColor = GDK_COLOR_RGB(0x00, 0x96, 0x14); // Green. const GdkColor kKeywordBackgroundColor = GDK_COLOR_RGB(0xf0, 0xf4, 0xfa); const GdkColor kKeywordBorderColor = GDK_COLOR_RGB(0xcb, 0xde, 0xf7); @@ -136,22 +131,19 @@ std::wstring CalculateMinString(const std::wstring& description) { // LocationBarViewGtk // static -const GdkColor LocationBarViewGtk::kBackgroundColor = - GDK_COLOR_RGB(255, 255, 255); - -LocationBarViewGtk::LocationBarViewGtk(Browser* browser) - : star_image_(NULL), - starred_(false), - security_icon_event_box_(NULL), - ev_secure_icon_image_(NULL), - secure_icon_image_(NULL), +const GdkColor LocationBarViewGtk::kBackgroundColorByLevel[3] = { + GDK_COLOR_RGB(255, 245, 195), // SecurityLevel SECURE: Yellow. + GDK_COLOR_RGB(255, 255, 255), // SecurityLevel NORMAL: White. + GDK_COLOR_RGB(255, 255, 255), // SecurityLevel INSECURE: White. +}; + +LocationBarViewGtk::LocationBarViewGtk( + const BubblePositioner* bubble_positioner, + Browser* browser) + : security_icon_event_box_(NULL), + security_lock_icon_image_(NULL), security_warning_icon_image_(NULL), - security_error_icon_image_(NULL), - site_type_alignment_(NULL), - site_type_event_box_(NULL), - location_icon_image_(NULL), - enable_location_drag_(false), - security_info_label_(NULL), + info_label_(NULL), tab_to_search_box_(NULL), tab_to_search_full_label_(NULL), tab_to_search_partial_label_(NULL), @@ -159,10 +151,12 @@ LocationBarViewGtk::LocationBarViewGtk(Browser* browser) tab_to_search_hint_leading_label_(NULL), tab_to_search_hint_icon_(NULL), tab_to_search_hint_trailing_label_(NULL), + type_to_search_hint_(NULL), profile_(NULL), command_updater_(browser->command_updater()), toolbar_model_(browser->toolbar_model()), browser_(browser), + bubble_positioner_(bubble_positioner), disposition_(CURRENT_TAB), transition_(PageTransition::TYPED), first_run_bubble_(this), @@ -170,12 +164,12 @@ LocationBarViewGtk::LocationBarViewGtk(Browser* browser) theme_provider_(NULL), entry_box_width_(0), show_selected_keyword_(false), - show_keyword_hint_(false) { + show_keyword_hint_(false), + show_search_hint_(false) { } LocationBarViewGtk::~LocationBarViewGtk() { // All of our widgets should have be children of / owned by the alignment. - star_.Destroy(); hbox_.Destroy(); content_setting_hbox_.Destroy(); page_action_hbox_.Destroy(); @@ -183,8 +177,14 @@ LocationBarViewGtk::~LocationBarViewGtk() { void LocationBarViewGtk::Init(bool popup_window_mode) { popup_window_mode_ = popup_window_mode; + location_entry_.reset(new AutocompleteEditViewGtk(this, + toolbar_model_, + profile_, + command_updater_, + popup_window_mode_, + bubble_positioner_)); + location_entry_->Init(); - // Create the widget first, so we can pass it to the AutocompleteEditViewGtk. hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding)); gtk_container_set_border_width(GTK_CONTAINER(hbox_.get()), kHboxBorder); // We will paint for the alignment, to paint the background and border. @@ -193,23 +193,30 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { // the home button on/off. gtk_widget_set_redraw_on_allocate(hbox_.get(), TRUE); - // Now initialize the AutocompleteEditViewGtk. - location_entry_.reset(new AutocompleteEditViewGtk(this, - toolbar_model_, - profile_, - command_updater_, - popup_window_mode_, - hbox_.get())); - location_entry_->Init(); + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + security_lock_icon_image_ = gtk_image_new_from_pixbuf( + rb.GetPixbufNamed(IDR_LOCK)); + gtk_widget_set_name(security_lock_icon_image_, "chrome-security-lock-icon"); + gtk_widget_hide(GTK_WIDGET(security_lock_icon_image_)); + security_warning_icon_image_ = gtk_image_new(); + gtk_widget_set_name(security_warning_icon_image_, + "chrome-security-warning-icon"); + gtk_widget_hide(GTK_WIDGET(security_warning_icon_image_)); + + info_label_ = gtk_label_new(NULL); + gtk_widget_modify_base(info_label_, GTK_STATE_NORMAL, + &LocationBarViewGtk::kBackgroundColorByLevel[0]); + gtk_widget_hide(GTK_WIDGET(info_label_)); + gtk_widget_set_name(info_label_, + "chrome-location-bar-info-label"); g_signal_connect(hbox_.get(), "expose-event", G_CALLBACK(&HandleExposeThunk), this); - BuildSiteTypeArea(); - - // Put |tab_to_search_box_|, |location_entry_|, and |tab_to_search_hint_| into - // a sub hbox, so that we can make this part horizontally shrinkable without - // affecting other elements in the location bar. + // Put |tab_to_search_box_|, |location_entry_|, |tab_to_search_hint_| and + // |type_to_search_hint_| into a sub hbox, so that we can make this part + // horizontally shrinkable without affecting other elements in the location + // bar. GtkWidget* entry_box = gtk_hbox_new(FALSE, kInnerPadding); gtk_widget_show(entry_box); gtk_widget_set_size_request(entry_box, 0, -1); @@ -230,22 +237,13 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { tab_to_search_full_label_, 0, 0); gtk_fixed_put(GTK_FIXED(tab_to_search_label_fixed), tab_to_search_partial_label_, 0, 0); - GtkWidget* tab_to_search_hbox = gtk_hbox_new(FALSE, 0); - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - GtkWidget* tab_to_search_lens = gtk_image_new_from_pixbuf( - rb.GetPixbufNamed(IDR_OMNIBOX_SEARCH)); - gtk_box_pack_start(GTK_BOX(tab_to_search_hbox), tab_to_search_lens, - FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(tab_to_search_hbox), tab_to_search_label_fixed, - FALSE, FALSE, 0); // This creates a box around the keyword text with a border, background color, // and padding around the text. tab_to_search_box_ = gtk_util::CreateGtkBorderBin( - tab_to_search_hbox, NULL, 1, 1, 1, 3); + tab_to_search_label_fixed, NULL, 1, 1, 2, 2); gtk_widget_set_name(tab_to_search_box_, "chrome-tab-to-search-box"); - gtk_util::ActAsRoundedWindow(tab_to_search_box_, kKeywordBorderColor, - kCornerSize, + gtk_util::ActAsRoundedWindow(tab_to_search_box_, kBorderColor, kCornerSize, gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL); // Show all children widgets of |tab_to_search_box_| initially, except // |tab_to_search_partial_label_|. @@ -271,7 +269,7 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { kBottomMargin + kBorderThickness, 0, 0); } - gtk_container_add(GTK_CONTAINER(align), location_entry_->GetNativeView()); + gtk_container_add(GTK_CONTAINER(align), location_entry_->widget()); gtk_box_pack_start(GTK_BOX(entry_box), align, TRUE, TRUE, 0); // Tab to search notification (the hint on the right hand side). @@ -299,11 +297,36 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { // doesn't work, someone is probably calling show_all on our parent box. gtk_box_pack_end(GTK_BOX(entry_box), tab_to_search_hint_, FALSE, FALSE, 0); - // We don't show the star in popups, app windows, etc. - if (!ShouldOnlyShowLocation()) { - CreateStarButton(); - gtk_box_pack_end(GTK_BOX(hbox_.get()), star_.get(), FALSE, FALSE, 0); - } + // Type to search hint is on the right hand side. + type_to_search_hint_ = + gtk_label_new(l10n_util::GetStringUTF8(IDS_OMNIBOX_EMPTY_TEXT).c_str()); + gtk_widget_set_sensitive(type_to_search_hint_, FALSE); + gtk_box_pack_end(GTK_BOX(entry_box), type_to_search_hint_, FALSE, FALSE, 0); + + // Pack info_label_ and security icons in hbox. We hide/show them + // by SetSecurityIcon() and SetInfoText(). + gtk_box_pack_end(GTK_BOX(hbox_.get()), info_label_, FALSE, FALSE, 0); + + GtkWidget* security_icon_box = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(security_icon_box), + security_lock_icon_image_, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(security_icon_box), + security_warning_icon_image_, FALSE, FALSE, 0); + + // GtkImage is a "no window" widget and requires a GtkEventBox to receive + // events. + security_icon_event_box_ = gtk_event_box_new(); + // Make the event box not visible so it does not paint a background. + gtk_event_box_set_visible_window(GTK_EVENT_BOX(security_icon_event_box_), + FALSE); + g_signal_connect(security_icon_event_box_, "button-press-event", + G_CALLBACK(&OnSecurityIconPressed), this); + + gtk_container_add(GTK_CONTAINER(security_icon_event_box_), security_icon_box); + gtk_widget_set_name(security_icon_event_box_, + "chrome-security-icon-eventbox"); + gtk_box_pack_end(GTK_BOX(hbox_.get()), security_icon_event_box_, + FALSE, FALSE, 0); content_setting_hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding)); gtk_widget_set_name(content_setting_hbox_.get(), @@ -327,7 +350,9 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { FALSE, FALSE, 0); // Until we switch to vector graphics, force the font size of labels. - gtk_util::ForceFontSizePixels(security_info_label_, + gtk_util::ForceFontSizePixels(type_to_search_hint_, + browser_defaults::kAutocompleteEditFontPixelSize); + gtk_util::ForceFontSizePixels(info_label_, browser_defaults::kAutocompleteEditFontPixelSize); gtk_util::ForceFontSizePixels(tab_to_search_full_label_, browser_defaults::kAutocompleteEditFontPixelSize); @@ -337,6 +362,8 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { browser_defaults::kAutocompleteEditFontPixelSize); gtk_util::ForceFontSizePixels(tab_to_search_hint_trailing_label_, browser_defaults::kAutocompleteEditFontPixelSize); + gtk_util::ForceFontSizePixels(type_to_search_hint_, + browser_defaults::kAutocompleteEditFontPixelSize); registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, @@ -345,71 +372,6 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { theme_provider_->InitThemesFor(this); } -void LocationBarViewGtk::BuildSiteTypeArea() { - location_icon_image_ = gtk_image_new(); - gtk_widget_set_name(location_icon_image_, "chrome-location-icon"); - gtk_widget_show(location_icon_image_); - - security_info_label_ = gtk_label_new(NULL); - gtk_widget_modify_fg(GTK_WIDGET(security_info_label_), GTK_STATE_NORMAL, - &kEvSecureTextColor); - gtk_widget_set_name(security_info_label_, - "chrome-location-bar-security-info-label"); - - GtkWidget* site_type_hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(site_type_hbox), location_icon_image_, - FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(site_type_hbox), security_info_label_, - FALSE, FALSE, kCornerSize); - - site_type_event_box_ = gtk_event_box_new(); - gtk_widget_modify_bg(site_type_event_box_, GTK_STATE_NORMAL, - &kEvSecureBackgroundColor); - - // Make the event box not visible so it does not paint a background. - gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_), - FALSE); - gtk_widget_set_name(site_type_event_box_, - "chrome-location-icon-eventbox"); - gtk_container_add(GTK_CONTAINER(site_type_event_box_), - site_type_hbox); - - // Put the event box in an alignment to get the padding correct. - site_type_alignment_ = gtk_alignment_new(0, 0, 1, 1); - gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_), - 0, 0, 1, 0); - gtk_container_add(GTK_CONTAINER(site_type_alignment_), - site_type_event_box_); - gtk_box_pack_start(GTK_BOX(hbox_.get()), site_type_alignment_, - FALSE, FALSE, 0); - - // Set up drags. -} - -void LocationBarViewGtk::SetSiteTypeDragSource() { - bool enable = !location_entry()->IsEditingOrEmpty(); - if (enable_location_drag_ == enable) - return; - enable_location_drag_ = enable; - - if (!enable) { - gtk_drag_source_unset(site_type_event_box_); - return; - } - - gtk_drag_source_set(site_type_event_box_, GDK_BUTTON1_MASK, - NULL, 0, GDK_ACTION_COPY); - gtk_dnd_util::SetSourceTargetListFromCodeMask(site_type_event_box_, - gtk_dnd_util::TEXT_PLAIN | - gtk_dnd_util::TEXT_URI_LIST | - gtk_dnd_util::CHROME_NAMED_URL); - - g_signal_connect(site_type_event_box_, "button-release-event", - G_CALLBACK(&OnIconReleasedThunk), this); - g_signal_connect(site_type_event_box_, "drag-data-get", - G_CALLBACK(&OnIconDragDataThunk), this); -} - void LocationBarViewGtk::SetProfile(Profile* profile) { profile_ = profile; } @@ -448,9 +410,10 @@ GtkWidget* LocationBarViewGtk::GetPageActionWidget( } void LocationBarViewGtk::Update(const TabContents* contents) { - UpdateSiteTypeArea(); + SetSecurityIcon(toolbar_model_->GetIcon()); UpdateContentSettingsIcons(); UpdatePageActions(); + SetInfoText(); location_entry_->Update(contents); // The security level (background color) could have changed, etc. if (theme_provider_->UseGtkTheme()) { @@ -498,12 +461,12 @@ void LocationBarViewGtk::OnAutocompleteAccept(const GURL& url, } void LocationBarViewGtk::OnChanged() { - UpdateSiteTypeArea(); - const std::wstring keyword(location_entry_->model()->keyword()); const bool is_keyword_hint = location_entry_->model()->is_keyword_hint(); show_selected_keyword_ = !keyword.empty() && !is_keyword_hint; show_keyword_hint_ = !keyword.empty() && is_keyword_hint; + show_search_hint_ = location_entry_->model()->show_search_hint(); + DCHECK(keyword.empty() || !show_search_hint_); if (show_selected_keyword_) SetKeywordLabel(keyword); @@ -514,20 +477,6 @@ void LocationBarViewGtk::OnChanged() { AdjustChildrenVisibility(); } -void LocationBarViewGtk::CreateStarButton() { - star_.Own(gtk_event_box_new()); - gtk_event_box_set_visible_window(GTK_EVENT_BOX(star_.get()), FALSE); - star_image_ = gtk_image_new(); - gtk_container_add(GTK_CONTAINER(star_.get()), star_image_); - gtk_widget_show_all(star_.get()); - ViewIDUtil::SetID(star_.get(), VIEW_ID_STAR_BUTTON); - - gtk_widget_set_tooltip_text(star_.get(), - l10n_util::GetStringUTF8(IDS_TOOLTIP_STAR).c_str()); - g_signal_connect(star_.get(), "button-press-event", - G_CALLBACK(OnStarButtonPressThunk), this); -} - void LocationBarViewGtk::OnInputInProgress(bool in_progress) { // This is identical to the Windows code, except that we don't proxy the call // back through the Toolbar, and just access the model here. @@ -662,7 +611,7 @@ void LocationBarViewGtk::UpdatePageActions() { // If there are no visible page actions, hide the hbox too, so that it does // not affect the padding in the location bar. - if (PageActionVisibleCount() && !ShouldOnlyShowLocation()) + if (PageActionVisibleCount()) gtk_widget_show(page_action_hbox_.get()); else gtk_widget_hide(page_action_hbox_.get()); @@ -741,6 +690,11 @@ void LocationBarViewGtk::Observe(NotificationType type, gtk_util::SetLabelColor(tab_to_search_partial_label_, NULL); gtk_util::SetLabelColor(tab_to_search_hint_leading_label_, NULL); gtk_util::SetLabelColor(tab_to_search_hint_trailing_label_, NULL); + gtk_util::SetLabelColor(type_to_search_hint_, NULL); + + gtk_image_set_from_stock(GTK_IMAGE(security_warning_icon_image_), + GTK_STOCK_DIALOG_WARNING, + GTK_ICON_SIZE_SMALL_TOOLBAR); } else { gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL, &kKeywordBackgroundColor); @@ -753,11 +707,12 @@ void LocationBarViewGtk::Observe(NotificationType type, &kHintTextColor); gtk_util::SetLabelColor(tab_to_search_hint_trailing_label_, &kHintTextColor); - } + gtk_util::SetLabelColor(type_to_search_hint_, &kHintTextColor); - UpdateStarIcon(); - UpdateSiteTypeArea(); - UpdateContentSettingsIcons(); + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + gtk_image_set_from_pixbuf(GTK_IMAGE(security_warning_icon_image_), + rb.GetPixbufNamed(IDR_WARNING)); + } } gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget, @@ -790,7 +745,8 @@ gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget, alloc_rect->width, alloc_rect->height - kTopMargin - kBottomMargin - 2 * kBorderThickness); - gdk_cairo_set_source_color(cr, const_cast(&kBackgroundColor)); + gdk_cairo_set_source_color(cr, const_cast( + &kBackgroundColorByLevel[toolbar_model_->GetSchemeSecurityLevel()])); cairo_fill(cr); cairo_destroy(cr); @@ -799,52 +755,45 @@ gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget, return FALSE; // Continue propagating the expose. } -void LocationBarViewGtk::UpdateSiteTypeArea() { - // The icon is always visible except when the |tab_to_search_box_| is visible. - if (!location_entry_->model()->keyword().empty() && - !location_entry_->model()->is_keyword_hint()) { - gtk_widget_hide(site_type_area()); - return; +void LocationBarViewGtk::SetSecurityIcon(ToolbarModel::Icon icon) { + gtk_widget_hide(GTK_WIDGET(security_lock_icon_image_)); + gtk_widget_hide(GTK_WIDGET(security_warning_icon_image_)); + if (icon != ToolbarModel::NO_ICON) + gtk_widget_show(GTK_WIDGET(security_icon_event_box_)); + else + gtk_widget_hide(GTK_WIDGET(security_icon_event_box_)); + switch (icon) { + case ToolbarModel::LOCK_ICON: + gtk_widget_show(GTK_WIDGET(security_lock_icon_image_)); + break; + case ToolbarModel::WARNING_ICON: + gtk_widget_show(GTK_WIDGET(security_warning_icon_image_)); + break; + case ToolbarModel::NO_ICON: + break; + default: + NOTREACHED(); + break; } +} - int resource_id = location_entry_->GetIcon(); - gtk_image_set_from_pixbuf(GTK_IMAGE(location_icon_image_), - theme_provider_->GetPixbufNamed(resource_id)); - - if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) { - if (!gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) { - // Fun fact: If wee try to make |site_type_event_box_| act as a - // rounded window while it doesn't have a visible window, GTK interprets - // this as a sign that it should paint the skyline texture into the - // omnibox. - gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_), - TRUE); - - gtk_util::ActAsRoundedWindow(site_type_event_box_, - kEvSecureBorderColor, - kCornerSize, - gtk_util::ROUNDED_ALL, - gtk_util::BORDER_ALL); - } - - std::wstring info_text = toolbar_model_->GetEVCertName(); - gtk_label_set_text(GTK_LABEL(security_info_label_), - WideToUTF8(info_text).c_str()); - gtk_widget_show(GTK_WIDGET(security_info_label_)); +void LocationBarViewGtk::SetInfoText() { + std::wstring info_text, info_tooltip; + ToolbarModel::InfoTextType info_text_type = + toolbar_model_->GetInfoText(&info_text, &info_tooltip); + if (info_text_type == ToolbarModel::INFO_EV_TEXT) { + gtk_widget_modify_fg(GTK_WIDGET(info_label_), GTK_STATE_NORMAL, + &kEvTextColor); + gtk_widget_show(GTK_WIDGET(info_label_)); } else { - if (gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) { - gtk_util::StopActingAsRoundedWindow(site_type_event_box_); - - gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_), - FALSE); - } - - gtk_widget_hide(GTK_WIDGET(security_info_label_)); + DCHECK_EQ(info_text_type, ToolbarModel::INFO_NO_INFO); + DCHECK(info_text.empty()); + // Clear info_text. Should we reset the fg here? + gtk_widget_hide(GTK_WIDGET(info_label_)); } - - gtk_widget_show(site_type_area()); - - SetSiteTypeDragSource(); + gtk_label_set_text(GTK_LABEL(info_label_), WideToUTF8(info_text).c_str()); + gtk_widget_set_tooltip_text(GTK_WIDGET(info_label_), + WideToUTF8(info_tooltip).c_str()); } void LocationBarViewGtk::SetKeywordLabel(const std::wstring& keyword) { @@ -915,114 +864,46 @@ void LocationBarViewGtk::ShowFirstRunBubbleInternal( FirstRunBubble::Show(profile_, anchor, rect, bubble_type); } -gboolean LocationBarViewGtk::OnIconReleased(GtkWidget* sender, - GdkEventButton* event) { - TabContents* tab = GetTabContents(); - - if (event->button == 1) { - // Do not show page info if the user has been editing the location - // bar, or the location bar is at the NTP. - if (location_entry()->IsEditingOrEmpty()) - return FALSE; - - // (0,0) event coordinates indicates that the release came at the end of - // a drag. - if (event->x == 0 && event->y == 0) - return FALSE; - - NavigationEntry* nav_entry = tab->controller().GetActiveEntry(); - if (!nav_entry) { - NOTREACHED(); - return FALSE; - } - tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true); - return TRUE; - } else if (event->button == 2) { - // When the user middle clicks on the location icon, try to open the - // contents of the PRIMARY selection in the current tab. - // If the click was outside our bounds, do nothing. - if (!gtk_util::WidgetBounds(sender).Contains( - gfx::Point(event->x, event->y))) { - return FALSE; - } - - GURL url; - if (!gtk_util::URLFromPrimarySelection(profile_, &url)) - return FALSE; - - tab->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED); - return TRUE; +// static +gboolean LocationBarViewGtk::OnSecurityIconPressed( + GtkWidget* sender, + GdkEventButton* event, + LocationBarViewGtk* location_bar) { + TabContents* tab = location_bar->GetTabContents(); + NavigationEntry* nav_entry = tab->controller().GetActiveEntry(); + if (!nav_entry) { + NOTREACHED(); + return true; } - - return FALSE; -} - -void LocationBarViewGtk::OnIconDragData(GtkWidget* sender, - GdkDragContext* context, - GtkSelectionData* data, - guint info, guint time) { - TabContents* tab = GetTabContents(); - if (!tab) - return; - gtk_dnd_util::WriteURLWithName(data, tab->GetURL(), tab->GetTitle(), info); + tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true); + return true; } -void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkWidget* sender, - GtkAllocation* allocation) { +void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkAllocation* allocation) { if (entry_box_width_ != allocation->width) { entry_box_width_ = allocation->width; AdjustChildrenVisibility(); } } -gboolean LocationBarViewGtk::OnStarButtonPress(GtkWidget* widget, - GdkEventButton* event) { - browser_->ExecuteCommand(IDC_BOOKMARK_PAGE); - return FALSE; -} - -void LocationBarViewGtk::ShowStarBubble(const GURL& url, - bool newly_bookmarked) { - if (!star_.get()) - return; - - BookmarkBubbleGtk::Show(star_.get(), profile_, url, newly_bookmarked); -} - -void LocationBarViewGtk::SetStarred(bool starred) { - if (starred == starred_) - return; - - starred_ = starred; - UpdateStarIcon(); -} - -void LocationBarViewGtk::UpdateStarIcon() { - if (!star_.get()) - return; - - gtk_image_set_from_pixbuf(GTK_IMAGE(star_image_), - theme_provider_->GetPixbufNamed( - starred_ ? IDR_OMNIBOX_STAR_LIT : IDR_OMNIBOX_STAR)); -} - -bool LocationBarViewGtk::ShouldOnlyShowLocation() { - return browser_->type() != Browser::TYPE_NORMAL; -} - void LocationBarViewGtk::AdjustChildrenVisibility() { int text_width = location_entry_->TextWidth(); int available_width = entry_box_width_ - text_width - kInnerPadding; - // Only one of |tab_to_search_box_| and |tab_to_search_hint_| can be visible - // at the same time. + // Only one of |tab_to_search_box_|, |tab_to_search_hint_| and + // |type_to_search_hint_| can be visible at the same time. if (!show_selected_keyword_ && GTK_WIDGET_VISIBLE(tab_to_search_box_)) { gtk_widget_hide(tab_to_search_box_); } else if (!show_keyword_hint_ && GTK_WIDGET_VISIBLE(tab_to_search_hint_)) { gtk_widget_hide(tab_to_search_hint_); location_entry_->set_enable_tab_to_search(false); + } else if (!show_search_hint_ && GTK_WIDGET_VISIBLE(type_to_search_hint_)) { + gtk_widget_hide(type_to_search_hint_); } + if (!show_selected_keyword_ && !show_keyword_hint_ && !show_search_hint_) + return; + if (show_selected_keyword_) { GtkRequisition box, full_label, partial_label; gtk_widget_size_request(tab_to_search_box_, &box); @@ -1071,6 +952,13 @@ void LocationBarViewGtk::AdjustChildrenVisibility() { gtk_widget_show(tab_to_search_hint_); location_entry_->set_enable_tab_to_search(true); } + } else if (show_search_hint_) { + GtkRequisition requisition; + gtk_widget_size_request(type_to_search_hint_, &requisition); + if (requisition.width >= available_width) + gtk_widget_hide(type_to_search_hint_); + else if (requisition.width < available_width) + gtk_widget_show(type_to_search_hint_); } } @@ -1108,12 +996,14 @@ LocationBarViewGtk::ContentSettingImageViewGtk::~ContentSettingImageViewGtk() { void LocationBarViewGtk::ContentSettingImageViewGtk::UpdateFromTabContents( const TabContents* tab_contents) { + int old_icon = content_setting_image_model_->get_icon(); content_setting_image_model_->UpdateFromTabContents(tab_contents); if (content_setting_image_model_->is_visible()) { - gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), - GtkThemeProvider::GetFrom(profile_)->GetPixbufNamed( + if (old_icon != content_setting_image_model_->get_icon()) { + gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), + ResourceBundle::GetSharedInstance().GetPixbufNamed( content_setting_image_model_->get_icon())); - + } gtk_widget_set_tooltip_text(widget(), content_setting_image_model_->get_tooltip().c_str()); gtk_widget_show(widget()); diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h index dd2db25..d31655b 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.h +++ b/chrome/browser/gtk/location_bar_view_gtk.h @@ -10,7 +10,6 @@ #include #include -#include "app/gtk_signal.h" #include "base/basictypes.h" #include "base/scoped_ptr.h" #include "base/scoped_vector.h" @@ -31,6 +30,7 @@ #include "webkit/glue/window_open_disposition.h" class AutocompleteEditViewGtk; +class BubblePositioner; class Browser; class CommandUpdater; class ContentSettingImageModel; @@ -47,7 +47,8 @@ class LocationBarViewGtk : public AutocompleteEditController, public LocationBarTesting, public NotificationObserver { public: - explicit LocationBarViewGtk(Browser* browser); + LocationBarViewGtk(const BubblePositioner* bubble_positioner, + Browser* browser_); virtual ~LocationBarViewGtk(); void Init(bool popup_window_mode); @@ -77,12 +78,6 @@ class LocationBarViewGtk : public AutocompleteEditController, // restore saved state that the tab holds. void Update(const TabContents* tab_for_state_restoring); - // Show the bookmark bubble. - void ShowStarBubble(const GURL& url, bool newly_boomkarked); - - // Set the starred state of the bookmark star. - void SetStarred(bool starred); - // Implement the AutocompleteEditController interface. virtual void OnAutocompleteAccept(const GURL& url, WindowOpenDisposition disposition, @@ -109,9 +104,6 @@ class LocationBarViewGtk : public AutocompleteEditController, virtual void InvalidatePageActions(); virtual void SaveStateToContents(TabContents* contents); virtual void Revert(); - virtual const AutocompleteEditView* location_entry() const { - return location_entry_.get(); - } virtual AutocompleteEditView* location_entry() { return location_entry_.get(); } @@ -129,8 +121,9 @@ class LocationBarViewGtk : public AutocompleteEditController, const NotificationSource& source, const NotificationDetails& details); - // Edit background color. - static const GdkColor kBackgroundColor; + // Translation between a security level and the background color. Both the + // location bar and edit have to manage and match the background color. + static const GdkColor kBackgroundColorByLevel[3]; private: class ContentSettingImageViewGtk : public InfoBubbleGtkDelegate { @@ -148,8 +141,12 @@ class LocationBarViewGtk : public AutocompleteEditController, void UpdateFromTabContents(const TabContents* tab_contents); private: - CHROMEGTK_CALLBACK_1(ContentSettingImageViewGtk, gboolean, OnButtonPressed, - GdkEvent*); + static gboolean OnButtonPressedThunk(GtkWidget* sender, + GdkEvent* event, + ContentSettingImageViewGtk* view) { + return view->OnButtonPressed(sender, event); + } + gboolean OnButtonPressed(GtkWidget* sender, GdkEvent* event); // InfoBubbleDelegate overrides: virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, @@ -211,10 +208,19 @@ class LocationBarViewGtk : public AutocompleteEditController, // with a debugger window attached. Returns true if a popup was shown. bool ShowPopup(bool devtools); - CHROMEGTK_CALLBACK_1(PageActionViewGtk, gboolean, OnButtonPressed, - GdkEvent*); - CHROMEGTK_CALLBACK_1(PageActionViewGtk, gboolean, OnExposeEvent, - GdkEventExpose*); + static gboolean OnButtonPressedThunk(GtkWidget* sender, + GdkEvent* event, + PageActionViewGtk* page_action_view) { + return page_action_view->OnButtonPressed(sender, event); + } + gboolean OnButtonPressed(GtkWidget* sender, GdkEvent* event); + + static gboolean OnExposeEventThunk(GtkWidget* widget, + GdkEventExpose* event, + PageActionViewGtk* page_action_view) { + return page_action_view->OnExposeEvent(widget, event); + } + gboolean OnExposeEvent(GtkWidget* widget, GdkEventExpose* event); // The location bar view that owns us. LocationBarViewGtk* owner_; @@ -262,30 +268,20 @@ class LocationBarViewGtk : public AutocompleteEditController, }; friend class PageActionViewGtk; - // Creates, initializes, and packs the location icon, EV certificate name, - // and optional border. - void BuildSiteTypeArea(); - - // Enable or disable the location icon/EV certificate as a drag source for - // the URL. - void SetSiteTypeDragSource(); + static gboolean HandleExposeThunk(GtkWidget* widget, GdkEventExpose* event, + gpointer userdata) { + return reinterpret_cast(userdata)-> + HandleExpose(widget, event); + } - GtkWidget* site_type_area() { return site_type_alignment_; } + gboolean HandleExpose(GtkWidget* widget, GdkEventExpose* event); - CHROMEGTK_CALLBACK_1(LocationBarViewGtk, gboolean, HandleExpose, - GdkEventExpose*); - CHROMEGTK_CALLBACK_1(LocationBarViewGtk, gboolean, OnIconReleased, - GdkEventButton*); - CHROMEGTK_CALLBACK_4(LocationBarViewGtk, void, OnIconDragData, - GdkDragContext*, GtkSelectionData*, guint, guint); - CHROMEGTK_CALLBACK_1(LocationBarViewGtk, void, OnEntryBoxSizeAllocate, - GtkAllocation*); - CHROMEGTK_CALLBACK_1(LocationBarViewGtk, gboolean, OnStarButtonPress, - GdkEventButton*); + static gboolean OnSecurityIconPressed(GtkWidget* sender, + GdkEventButton* event, + LocationBarViewGtk* location_bar); - // Updates the site type area: changes the icon and shows/hides the EV - // certificate information. - void UpdateSiteTypeArea(); + // Set the SSL icon we should be showing. + void SetSecurityIcon(ToolbarModel::Icon icon); // Sets the text that should be displayed in the info label and its associated // tooltip text. Call with an empty string if the info label should be @@ -300,43 +296,29 @@ class LocationBarViewGtk : public AutocompleteEditController, void ShowFirstRunBubbleInternal(FirstRun::BubbleType bubble_type); - // Show or hide |tab_to_search_box_| and |tab_to_search_hint_| according to - // the value of |show_selected_keyword_|, |show_keyword_hint_|, and the - // available horizontal space in the location bar. - void AdjustChildrenVisibility(); - - // Build the star icon. - void CreateStarButton(); - - // Update the star icon after it is toggled or the theme changes. - void UpdateStarIcon(); + static void OnEntryBoxSizeAllocateThunk(GtkWidget* widget, + GtkAllocation* allocation, + gpointer userdata) { + reinterpret_cast(userdata)-> + OnEntryBoxSizeAllocate(allocation); + } + void OnEntryBoxSizeAllocate(GtkAllocation* allocation); - // Returns true if we should only show the URL and none of the extras like - // the star button or page actions. - bool ShouldOnlyShowLocation(); + // Show or hide |tab_to_search_box_|, |tab_to_search_hint_| and + // |type_to_search_hint_| according to the value of |show_selected_keyword_|, + // |show_keyword_hint_|, |show_search_hint_| and the available horizontal + // space in the location bar. + void AdjustChildrenVisibility(); // The outermost widget we want to be hosted. OwnedWidgetGtk hbox_; - // Star button. - OwnedWidgetGtk star_; - GtkWidget* star_image_; - bool starred_; - - // SSL state. + // SSL icons. GtkWidget* security_icon_event_box_; - GtkWidget* ev_secure_icon_image_; - GtkWidget* secure_icon_image_; + GtkWidget* security_lock_icon_image_; GtkWidget* security_warning_icon_image_; - GtkWidget* security_error_icon_image_; - // An icon to the left of the address bar. - GtkWidget* site_type_alignment_; - GtkWidget* site_type_event_box_; - GtkWidget* location_icon_image_; - bool enable_location_drag_; - // TODO(pkasting): Split this label off and move the rest of the items to the - // left of the address bar. - GtkWidget* security_info_label_; + // Toolbar info text (EV cert info). + GtkWidget* info_label_; // Content setting icons. OwnedWidgetGtk content_setting_hbox_; @@ -357,6 +339,9 @@ class LocationBarViewGtk : public AutocompleteEditController, GtkWidget* tab_to_search_hint_icon_; GtkWidget* tab_to_search_hint_trailing_label_; + // Hint to user that the inputted text is not a keyword or url. + GtkWidget* type_to_search_hint_; + scoped_ptr location_entry_; Profile* profile_; @@ -364,6 +349,9 @@ class LocationBarViewGtk : public AutocompleteEditController, ToolbarModel* toolbar_model_; Browser* browser_; + // We need to hold on to this just to it pass to the edit. + const BubblePositioner* bubble_positioner_; + // When we get an OnAutocompleteAccept notification from the autocomplete // edit, we save the input string so we can give it back to the browser on // the LocationBar interface via GetInputString(). @@ -397,6 +385,9 @@ class LocationBarViewGtk : public AutocompleteEditController, // Indicate if |tab_to_search_hint_| should be shown. bool show_keyword_hint_; + // Indicate if |type_to_search_hint_| should be shown. + bool show_search_hint_; + DISALLOW_COPY_AND_ASSIGN(LocationBarViewGtk); }; diff --git a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc index 8162610..5488e4f 100644 --- a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc +++ b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc @@ -116,7 +116,7 @@ void PasswordsExceptionsPageGtk::SetExceptionList( for (size_t i = 0; i < result.size(); ++i) { exception_list_[i] = *result[i]; std::wstring formatted = net::FormatUrl(result[i]->origin, languages, - net::kFormatUrlOmitAll, UnescapeRule::NONE, NULL, NULL, NULL); + false, UnescapeRule::NONE, NULL, NULL, NULL); std::string site = WideToUTF8(formatted); GtkTreeIter iter; gtk_list_store_insert_with_values(exception_list_store_, &iter, (gint) i, diff --git a/chrome/browser/gtk/options/passwords_page_gtk.cc b/chrome/browser/gtk/options/passwords_page_gtk.cc index 9ecf89f..0de0403 100644 --- a/chrome/browser/gtk/options/passwords_page_gtk.cc +++ b/chrome/browser/gtk/options/passwords_page_gtk.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -160,7 +160,7 @@ void PasswordsPageGtk::SetPasswordList( for (size_t i = 0; i < result.size(); ++i) { password_list_[i] = *result[i]; std::wstring formatted = net::FormatUrl(result[i]->origin, languages, - net::kFormatUrlOmitAll, UnescapeRule::NONE, NULL, NULL, NULL); + false, UnescapeRule::NONE, NULL, NULL, NULL); std::string site = WideToUTF8(formatted); std::string user = UTF16ToUTF8(result[i]->username_value); GtkTreeIter iter; diff --git a/chrome/browser/gtk/options/url_picker_dialog_gtk.cc b/chrome/browser/gtk/options/url_picker_dialog_gtk.cc index b5e5a5b..df45b14 100644 --- a/chrome/browser/gtk/options/url_picker_dialog_gtk.cc +++ b/chrome/browser/gtk/options/url_picker_dialog_gtk.cc @@ -198,8 +198,7 @@ std::string UrlPickerDialogGtk::GetURLForPath(GtkTreePath* path) const { // Because the url_field_ is user-editable, we set the URL with // username:password and escaped path and query. std::wstring formatted = net::FormatUrl(url_table_model_->GetURL(row), - languages, net::kFormatUrlOmitNothing, UnescapeRule::NONE, NULL, NULL, - NULL); + languages, false, UnescapeRule::NONE, NULL, NULL, NULL); return WideToUTF8(formatted); } diff --git a/chrome/browser/gtk/rounded_window.cc b/chrome/browser/gtk/rounded_window.cc index 52bedc9..540a465 100644 --- a/chrome/browser/gtk/rounded_window.cc +++ b/chrome/browser/gtk/rounded_window.cc @@ -287,10 +287,6 @@ void StopActingAsRoundedWindow(GtkWidget* widget) { gdk_window_shape_combine_mask(widget->window, NULL, 0, 0); } -bool IsActingAsRoundedWindow(GtkWidget* widget) { - return g_object_get_data(G_OBJECT(widget), kRoundedData) != NULL; -} - void SetRoundedWindowEdgesAndBorders(GtkWidget* widget, int corner_size, int rounded_edges, diff --git a/chrome/browser/gtk/rounded_window.h b/chrome/browser/gtk/rounded_window.h index cd98e71..95f91d9 100644 --- a/chrome/browser/gtk/rounded_window.h +++ b/chrome/browser/gtk/rounded_window.h @@ -42,9 +42,6 @@ void ActAsRoundedWindow( // Undoes most of the actions of ActAsRoundedWindow(). void StopActingAsRoundedWindow(GtkWidget* widget); -// Returns true if the window is rounded. -bool IsActingAsRoundedWindow(GtkWidget* widget); - // Sets edge and border properties on a widget that has already been configured // with ActAsRoundedWindow(). void SetRoundedWindowEdgesAndBorders(GtkWidget* widget, diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc index 8d1d1c8..25a02c3 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc @@ -1980,8 +1980,28 @@ void TabStripGtk::OnNewTabClicked(GtkWidget* widget, TabStripGtk* tabstrip) { case 2: { // On middle-click, try to parse the PRIMARY selection as a URL and load // it instead of creating a blank page. - GURL url; - if (!gtk_util::URLFromPrimarySelection(tabstrip->model_->profile(), &url)) + GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); + DCHECK(clipboard); + gchar* selection_text = gtk_clipboard_wait_for_text(clipboard); + if (!selection_text) + return; + + // Use autocomplete to clean up the text, going so far as to turn it into + // a search query if necessary. + AutocompleteController controller(tabstrip->model_->profile()); + controller.Start(UTF8ToWide(selection_text), + std::wstring(), // desired_tld + true, // prevent_inline_autocomplete + false, // prefer_keyword + true); // synchronous_only + g_free(selection_text); + const AutocompleteResult& result = controller.result(); + AutocompleteResult::const_iterator it = result.default_match(); + if (it == result.end()) + return; + + GURL url(it->destination_url); + if (!url.is_valid()) return; TabContents* contents = diff --git a/chrome/browser/gtk/toolbar_star_toggle_gtk.cc b/chrome/browser/gtk/toolbar_star_toggle_gtk.cc new file mode 100644 index 0000000..a57d79e --- /dev/null +++ b/chrome/browser/gtk/toolbar_star_toggle_gtk.cc @@ -0,0 +1,142 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/gtk/toolbar_star_toggle_gtk.h" + +#include "app/gtk_dnd_util.h" +#include "app/resource_bundle.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/gtk/bookmark_bubble_gtk.h" +#include "chrome/browser/gtk/browser_toolbar_gtk.h" +#include "chrome/browser/gtk/gtk_chrome_button.h" +#include "chrome/browser/gtk/gtk_theme_provider.h" +#include "chrome/browser/gtk/gtk_util.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/notification_service.h" +#include "gfx/rect.h" +#include "grit/theme_resources.h" + +ToolbarStarToggleGtk::ToolbarStarToggleGtk(BrowserToolbarGtk* host) + : host_(host), + widget_(gtk_chrome_button_new()), + is_starred_(false), + theme_provider_(GtkThemeProvider::GetFrom(host->profile())), + unstarred_(theme_provider_, IDR_STAR, IDR_STAR_P, IDR_STAR_H, IDR_STAR_D, + IDR_STAR_MASK), + starred_(theme_provider_, IDR_STARRED, IDR_STARRED_P, IDR_STARRED_H, 0, + IDR_STAR_MASK) { + gtk_widget_set_size_request(widget_.get(), unstarred_.Width(), + unstarred_.Height()); + + gtk_widget_set_app_paintable(widget_.get(), TRUE); + // We effectively double-buffer by virtue of having only one image... + gtk_widget_set_double_buffered(widget_.get(), FALSE); + + g_signal_connect(widget(), "expose-event", + G_CALLBACK(OnExpose), this); + GTK_WIDGET_UNSET_FLAGS(widget(), GTK_CAN_FOCUS); + + gtk_drag_source_set(widget(), GDK_BUTTON1_MASK, NULL, 0, + static_cast(GDK_ACTION_COPY | GDK_ACTION_LINK)); + gtk_dnd_util::SetSourceTargetListFromCodeMask(widget(), + gtk_dnd_util::TEXT_PLAIN | + gtk_dnd_util::TEXT_URI_LIST | + gtk_dnd_util::CHROME_NAMED_URL | + gtk_dnd_util::NETSCAPE_URL); + g_signal_connect(widget(), "drag-data-get", G_CALLBACK(OnDragDataGet), this); + + theme_provider_->InitThemesFor(this); + registrar_.Add(this, + NotificationType::BROWSER_THEME_CHANGED, + NotificationService::AllSources()); + + hover_controller_.Init(widget()); +} + +ToolbarStarToggleGtk::~ToolbarStarToggleGtk() { + widget_.Destroy(); +} + +void ToolbarStarToggleGtk::Observe(NotificationType type, + const NotificationSource& source, const NotificationDetails& details) { + DCHECK(NotificationType::BROWSER_THEME_CHANGED == type); + + GtkThemeProvider* provider = static_cast( + Source(source).ptr()); + DCHECK(provider == theme_provider_); + UpdateGTKButton(); +} + +void ToolbarStarToggleGtk::ShowStarBubble(const GURL& url, + bool newly_bookmarked) { + GtkWidget* widget = widget_.get(); + BookmarkBubbleGtk::Show(GTK_WINDOW(gtk_widget_get_toplevel(widget)), + gtk_util::GetWidgetRectRelativeToToplevel(widget), + host_->profile(), + url, + newly_bookmarked); +} + +void ToolbarStarToggleGtk::SetStarred(bool starred) { + is_starred_ = starred; + gtk_widget_queue_draw(widget_.get()); + UpdateGTKButton(); +} + +// static +gboolean ToolbarStarToggleGtk::OnExpose(GtkWidget* widget, GdkEventExpose* e, + ToolbarStarToggleGtk* button) { + if (button->theme_provider_->UseGtkTheme()) { + return FALSE; + } else { + double hover_state = button->hover_controller_.GetCurrentValue(); + if (button->is_starred_) + return button->starred_.OnExpose(widget, e, hover_state); + else + return button->unstarred_.OnExpose(widget, e, hover_state); + } +} + +// static +void ToolbarStarToggleGtk::OnDragDataGet(GtkWidget* widget, + GdkDragContext* drag_context, GtkSelectionData* data, guint info, + guint time, ToolbarStarToggleGtk* star) { + const TabContents* tab = star->host_->browser()->tabstrip_model()-> + GetSelectedTabContents(); + if (!tab) + return; + gtk_dnd_util::WriteURLWithName(data, tab->GetURL(), tab->GetTitle(), info); +} + +void ToolbarStarToggleGtk::UpdateGTKButton() { + bool use_gtk = theme_provider_ && theme_provider_->UseGtkTheme(); + + if (use_gtk) { + GdkPixbuf* pixbuf = NULL; + if (is_starred_) { + pixbuf = theme_provider_->GetPixbufNamed(IDR_STARRED_NOBORDER_CENTER); + } else { + pixbuf = theme_provider_->GetPixbufNamed(IDR_STAR_NOBORDER_CENTER); + } + + gtk_button_set_image( + GTK_BUTTON(widget_.get()), + gtk_image_new_from_pixbuf(pixbuf)); + + gtk_widget_set_size_request(widget_.get(), -1, -1); + gtk_widget_set_app_paintable(widget_.get(), FALSE); + gtk_widget_set_double_buffered(widget_.get(), TRUE); + } else { + gtk_widget_set_size_request(widget_.get(), unstarred_.Width(), + unstarred_.Height()); + + gtk_widget_set_app_paintable(widget_.get(), TRUE); + // We effectively double-buffer by virtue of having only one image... + gtk_widget_set_double_buffered(widget_.get(), FALSE); + } + + gtk_chrome_button_set_use_gtk_rendering( + GTK_CHROME_BUTTON(widget_.get()), use_gtk); +} diff --git a/chrome/browser/gtk/toolbar_star_toggle_gtk.h b/chrome/browser/gtk/toolbar_star_toggle_gtk.h new file mode 100644 index 0000000..faa025a --- /dev/null +++ b/chrome/browser/gtk/toolbar_star_toggle_gtk.h @@ -0,0 +1,76 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_GTK_TOOLBAR_STAR_TOGGLE_GTK_H_ +#define CHROME_BROWSER_GTK_TOOLBAR_STAR_TOGGLE_GTK_H_ + +#include + +#include "base/basictypes.h" +#include "chrome/browser/gtk/custom_button.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/owned_widget_gtk.h" + +class BrowserToolbarGtk; +class GtkThemeProvider; +class GURL; + +// Displays the bookmark star button, which toggles between two images. +class ToolbarStarToggleGtk : public NotificationObserver { + public: + explicit ToolbarStarToggleGtk(BrowserToolbarGtk* host); + ~ToolbarStarToggleGtk(); + + // Provide NotificationObserver implementation. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // If the bubble isn't showing, shows it above the star button. + void ShowStarBubble(const GURL& url, bool newly_bookmarked); + + void SetStarred(bool starred); + + GtkWidget* widget() const { return widget_.get(); } + + private: + // Updates the properties of |widget_| when we would need to change its + // state. + void UpdateGTKButton(); + + // Callback for expose, used to draw the custom graphics. + static gboolean OnExpose(GtkWidget* widget, GdkEventExpose* e, + ToolbarStarToggleGtk* obj); + + // Callback to get the data associated with a drag. + static void OnDragDataGet(GtkWidget* widget, + GdkDragContext* drag_context, + GtkSelectionData* data, + guint info, + guint time, + ToolbarStarToggleGtk* star); + + // Used to listen for theme change notifications. + NotificationRegistrar registrar_; + + // The browser toolbar hosting this widget, for getting the current profile. + BrowserToolbarGtk* host_; + + // The actual button widget. + OwnedWidgetGtk widget_; + + // Whether we show the yellow star. + bool is_starred_; + + GtkThemeProvider* theme_provider_; + + CustomDrawButtonBase unstarred_; + CustomDrawButtonBase starred_; + CustomDrawHoverController hover_controller_; + + DISALLOW_COPY_AND_ASSIGN(ToolbarStarToggleGtk); +}; + +#endif // CHROME_BROWSER_GTK_TOOLBAR_STAR_TOGGLE_GTK_H_ diff --git a/chrome/browser/location_bar.h b/chrome/browser/location_bar.h index a30dcf0..7919406 100644 --- a/chrome/browser/location_bar.h +++ b/chrome/browser/location_bar.h @@ -69,7 +69,6 @@ class LocationBar { virtual void Revert() = 0; // Returns a pointer to the text entry view. - virtual const AutocompleteEditView* location_entry() const = 0; virtual AutocompleteEditView* location_entry() = 0; // Returns a pointer to the testing interface. diff --git a/chrome/browser/net/browser_url_util.cc b/chrome/browser/net/browser_url_util.cc index 24747b2..9c8ab48 100644 --- a/chrome/browser/net/browser_url_util.cc +++ b/chrome/browser/net/browser_url_util.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -23,8 +23,8 @@ void WriteURLToClipboard(const GURL& url, // may not encode non-ASCII characters in UTF-8. See crbug.com/2820. string16 text = url.SchemeIs(chrome::kMailToScheme) ? ASCIIToUTF16(url.path()) : - WideToUTF16(net::FormatUrl(url, languages, net::kFormatUrlOmitNothing, - UnescapeRule::NONE, NULL, NULL, NULL)); + WideToUTF16(net::FormatUrl(url, languages, false, UnescapeRule::NONE, + NULL, NULL, NULL)); ScopedClipboardWriter scw(clipboard); scw.WriteURL(text); diff --git a/chrome/browser/net/url_fixer_upper.cc b/chrome/browser/net/url_fixer_upper.cc index 9d974db..edacefd 100644 --- a/chrome/browser/net/url_fixer_upper.cc +++ b/chrome/browser/net/url_fixer_upper.cc @@ -170,9 +170,8 @@ static std::string FixupPath(const std::string& text) { // Here, we know the input looks like a file. GURL file_url = net::FilePathToFileURL(FilePath(filename)); if (file_url.is_valid()) { - return WideToUTF8(net::FormatUrl(file_url, std::wstring(), - net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, NULL, - NULL, NULL)); + return WideToUTF8(net::FormatUrl(file_url, std::wstring(), true, + UnescapeRule::NORMAL, NULL, NULL, NULL)); } // Invalid file URL, just return the input. @@ -558,8 +557,7 @@ std::string URLFixerUpper::FixupRelativeFile(const FilePath& base_dir, GURL file_url = net::FilePathToFileURL(full_path); if (file_url.is_valid()) return WideToUTF8(net::FormatUrl(file_url, std::wstring(), - net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, NULL, - NULL, NULL)); + true, UnescapeRule::NORMAL, NULL, NULL, NULL)); // Invalid files fall through to regular processing. } diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 92b2ff8..ed480e8 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -13,7 +13,6 @@ #include "base/scoped_ptr.h" #include "base/string_util.h" #include "chrome/browser/appcache/chrome_appcache_service.h" -#include "chrome/browser/autocomplete/autocomplete_classifier.h" #include "chrome/browser/autofill/personal_data_manager.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/browser_list.h" @@ -46,6 +45,7 @@ #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h" #include "chrome/browser/profile_manager.h" #include "chrome/browser/renderer_host/render_process_host.h" +#include "chrome/browser/search_versus_navigate_classifier.h" #include "chrome/browser/search_engines/template_url_fetcher.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/sessions/session_service.h" @@ -338,8 +338,8 @@ class OffTheRecordProfileImpl : public Profile, return NULL; } - virtual AutocompleteClassifier* GetAutocompleteClassifier() { - return profile_->GetAutocompleteClassifier(); + virtual SearchVersusNavigateClassifier* GetSearchVersusNavigateClassifier() { + return profile_->GetSearchVersusNavigateClassifier(); } virtual WebDataService* GetWebDataService(ServiceAccessType sat) { @@ -1139,10 +1139,13 @@ TemplateURLFetcher* ProfileImpl::GetTemplateURLFetcher() { return template_url_fetcher_.get(); } -AutocompleteClassifier* ProfileImpl::GetAutocompleteClassifier() { - if (!autocomplete_classifier_.get()) - autocomplete_classifier_.reset(new AutocompleteClassifier(this)); - return autocomplete_classifier_.get(); +SearchVersusNavigateClassifier* +ProfileImpl::GetSearchVersusNavigateClassifier() { + if (!search_versus_navigate_classifier_.get()) { + search_versus_navigate_classifier_.reset( + new SearchVersusNavigateClassifier(this)); + } + return search_versus_navigate_classifier_.get(); } WebDataService* ProfileImpl::GetWebDataService(ServiceAccessType sat) { diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 751d2e2..a4f680ad 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -30,7 +30,6 @@ namespace webkit_database { class DatabaseTracker; } -class AutocompleteClassifier; class Blacklist; class BookmarkModel; class BrowserThemeProvider; @@ -56,6 +55,7 @@ class PinnedTabService; class PrefService; class ProfileSyncService; class ProfileSyncFactory; +class SearchVersusNavigateClassifier; class SessionService; class SpellCheckHost; class SSLConfigServiceManager; @@ -217,10 +217,11 @@ class Profile { // doesn't already exist. virtual HistoryService* GetHistoryServiceWithoutCreating() = 0; - // Retrieves a pointer to the AutocompleteClassifier associated with this - // profile. The AutocompleteClassifier is lazily created the first time that - // this method is called. - virtual AutocompleteClassifier* GetAutocompleteClassifier() = 0; + // Retrieves a pointer to the SearchVersusNavigateClassifier associated with + // this profile. The SearchVersusNavigateClassifier is lazily created the + // first time that this method is called. + virtual SearchVersusNavigateClassifier* + GetSearchVersusNavigateClassifier() = 0; // Returns the WebDataService for this profile. This is owned by // the Profile. Callers that outlive the life of this profile need to be @@ -472,7 +473,7 @@ class ProfileImpl : public Profile, virtual FaviconService* GetFaviconService(ServiceAccessType sat); virtual HistoryService* GetHistoryService(ServiceAccessType sat); virtual HistoryService* GetHistoryServiceWithoutCreating(); - virtual AutocompleteClassifier* GetAutocompleteClassifier(); + virtual SearchVersusNavigateClassifier* GetSearchVersusNavigateClassifier(); virtual WebDataService* GetWebDataService(ServiceAccessType sat); virtual WebDataService* GetWebDataServiceWithoutCreating(); virtual PasswordStore* GetPasswordStore(ServiceAccessType sat); @@ -597,7 +598,7 @@ class ProfileImpl : public Profile, scoped_refptr download_manager_; scoped_refptr history_service_; scoped_refptr favicon_service_; - scoped_ptr autocomplete_classifier_; + scoped_ptr search_versus_navigate_classifier_; scoped_refptr web_data_service_; scoped_refptr password_store_; scoped_refptr session_service_; diff --git a/chrome/browser/search_versus_navigate_classifier.cc b/chrome/browser/search_versus_navigate_classifier.cc new file mode 100644 index 0000000..b32b92b --- /dev/null +++ b/chrome/browser/search_versus_navigate_classifier.cc @@ -0,0 +1,56 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/search_versus_navigate_classifier.h" + +#include "chrome/browser/autocomplete/autocomplete.h" +#include "googleurl/src/gurl.h" + +SearchVersusNavigateClassifier::SearchVersusNavigateClassifier(Profile* profile) + : controller_(new AutocompleteController(profile)) { +} + +SearchVersusNavigateClassifier::~SearchVersusNavigateClassifier() { +} + +void SearchVersusNavigateClassifier::Classify(const std::wstring& text, + const std::wstring& desired_tld, + bool* is_search, + GURL* destination_url, + PageTransition::Type* transition, + bool* is_history_what_you_typed_match, + GURL* alternate_nav_url) { + controller_->Start(text, desired_tld, true, false, true); + DCHECK(controller_->done()); + const AutocompleteResult& result = controller_->result(); + if (result.empty()) { + if (is_search) + *is_search = false; + if (destination_url) + *destination_url = GURL(); + if (transition) + *transition = PageTransition::TYPED; + if (is_history_what_you_typed_match) + *is_history_what_you_typed_match = false; + if (alternate_nav_url) + *alternate_nav_url = GURL(); + return; + } + + const AutocompleteResult::const_iterator match(result.default_match()); + DCHECK(match != result.end()); + + // If this is a search, the page transition will be GENERATED rather than + // TYPED. + if (is_search) + *is_search = (match->transition != PageTransition::TYPED); + if (destination_url) + *destination_url = match->destination_url; + if (transition) + *transition = match->transition; + if (is_history_what_you_typed_match) + *is_history_what_you_typed_match = match->is_history_what_you_typed_match; + if (alternate_nav_url) + *alternate_nav_url = result.alternate_nav_url(); +} diff --git a/chrome/browser/search_versus_navigate_classifier.h b/chrome/browser/search_versus_navigate_classifier.h new file mode 100644 index 0000000..94471b8 --- /dev/null +++ b/chrome/browser/search_versus_navigate_classifier.h @@ -0,0 +1,52 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SEARCH_VERSUS_NAVIGATE_CLASSIFIER_H_ +#define CHROME_BROWSER_SEARCH_VERSUS_NAVIGATE_CLASSIFIER_H_ + +#include + +#include "base/scoped_ptr.h" +#include "chrome/common/page_transition_types.h" + +class AutocompleteController; +class GURL; +class Profile; + +class SearchVersusNavigateClassifier { + public: + explicit SearchVersusNavigateClassifier(Profile* profile); + virtual ~SearchVersusNavigateClassifier(); + + // Given some string |text| that the user wants to use for navigation, + // determines whether to treat it as a search query or a URL, and returns the + // details of the resulting navigation. + // NOTE: After |desired_tld|, all parameters are potentially-NULL outparams. + // |desired_tld| - User's desired TLD. + // See AutocompleteInput::desired_tld(). + // |is_search| - Set to true if this is to be treated as a + // query rather than URL. + // |destination_url| - The URL to load. It may be empty if there is no + // possible navigation (when |text| is empty). + // |transition| - The transition type. + // |is_history_what_you_typed_match| + // - Set to true when the default match is the + // "what you typed" match from the history. + // |alternate_nav_url| - The navigational URL in case of an accidental + // search; see comments on + // AutocompleteResult::alternate_nav_url_ in + // autocomplete.h. + void Classify(const std::wstring& text, + const std::wstring& desired_tld, + bool* is_search, + GURL* destination_url, + PageTransition::Type* transition, + bool* is_history_what_you_typed_match, + GURL* alternate_nav_url); + + private: + scoped_ptr controller_; +}; + +#endif // CHROME_BROWSER_SEARCH_VERSUS_NAVIGATE_CLASSIFIER_H_ diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc index d6ef458..fb3d447 100644 --- a/chrome/browser/ssl/ssl_browser_tests.cc +++ b/chrome/browser/ssl/ssl_browser_tests.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -65,9 +65,6 @@ class SSLUITest : public InProcessBrowserTest { entry->page_type()); EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, entry->ssl().security_style()); - // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION doesn't lower the security style - // to SECURITY_STYLE_AUTHENTICATION_BROKEN. - ASSERT_NE(net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION, error); EXPECT_EQ(error, entry->ssl().cert_status() & net::CERT_STATUS_ALL_ERRORS); EXPECT_FALSE(entry->ssl().has_mixed_content()); EXPECT_FALSE(entry->ssl().has_unsafe_content()); diff --git a/chrome/browser/ssl/ssl_manager.cc b/chrome/browser/ssl/ssl_manager.cc index 7683221..c1350e4 100644 --- a/chrome/browser/ssl/ssl_manager.cc +++ b/chrome/browser/ssl/ssl_manager.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -271,15 +271,30 @@ bool SSLManager::DeserializeSecurityInfo(const std::string& state, } // static -std::wstring SSLManager::GetEVCertName(const net::X509Certificate& cert) { +bool SSLManager::GetEVCertNames(const net::X509Certificate& cert, + std::wstring* short_name, + std::wstring* ca_name) { + DCHECK(short_name || ca_name); + // EV are required to have an organization name and country. if (cert.subject().organization_names.empty() || cert.subject().country_name.empty()) { NOTREACHED(); - return std::wstring(); + return false; } - return l10n_util::GetStringF(IDS_SECURE_CONNECTION_EV, - UTF8ToWide(cert.subject().organization_names[0]), - UTF8ToWide(cert.subject().country_name)); + if (short_name) { + *short_name = l10n_util::GetStringF( + IDS_SECURE_CONNECTION_EV, + UTF8ToWide(cert.subject().organization_names[0]), + UTF8ToWide(cert.subject().country_name)); + } + + if (ca_name) { + // TODO(wtc): should we show the root CA's name instead? + *ca_name = l10n_util::GetStringF( + IDS_SECURE_CONNECTION_EV_CA, + UTF8ToWide(cert.issuer().organization_names[0])); + } + return true; } diff --git a/chrome/browser/ssl/ssl_manager.h b/chrome/browser/ssl/ssl_manager.h index f9e1685..b0f18e1 100644 --- a/chrome/browser/ssl/ssl_manager.h +++ b/chrome/browser/ssl/ssl_manager.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -92,8 +92,12 @@ class SSLManager : public NotificationObserver { int* cert_status, int* security_bits); - // Returns " []". - static std::wstring GetEVCertName(const net::X509Certificate& cert); + // Sets |short_name| to [] and |ca_name| + // to something like: + // "Verified by " + static bool GetEVCertNames(const net::X509Certificate& cert, + std::wstring* short_name, + std::wstring* ca_name); private: // SSLMessageInfo contains the information necessary for displaying a message diff --git a/chrome/browser/ssl/ssl_policy.cc b/chrome/browser/ssl/ssl_policy.cc index 7f3ad87..9b4a6e9 100644 --- a/chrome/browser/ssl/ssl_policy.cc +++ b/chrome/browser/ssl/ssl_policy.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -67,9 +67,10 @@ void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) { handler->ContinueRequest(); break; case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: - // We ignore this error but will show a warning status in the location - // bar. + // We ignore this error and display an infobar. handler->ContinueRequest(); + backend_->ShowMessage(l10n_util::GetString( + IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_INFO_BAR)); break; case net::ERR_CERT_CONTAINS_ERRORS: case net::ERR_CERT_REVOKED: @@ -126,12 +127,8 @@ void SSLPolicy::UpdateEntry(NavigationEntry* entry) { return; } - // If CERT_STATUS_UNABLE_TO_CHECK_REVOCATION is the only certificate error, - // don't lower the security style to SECURITY_STYLE_AUTHENTICATION_BROKEN. - int cert_errors = entry->ssl().cert_status() & net::CERT_STATUS_ALL_ERRORS; - if (cert_errors) { - if (cert_errors != net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) - entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN); + if (net::IsCertStatusError(entry->ssl().cert_status())) { + entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN); return; } diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc index 471d2b8..105e95d 100644 --- a/chrome/browser/tab_contents/render_view_context_menu.cc +++ b/chrome/browser/tab_contents/render_view_context_menu.cc @@ -13,7 +13,6 @@ #include "base/logging.h" #include "base/string_util.h" #include "chrome/app/chrome_dll_resource.h" -#include "chrome/browser/autocomplete/autocomplete_classifier.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/child_process_security_policy.h" #include "chrome/browser/debugger/devtools_manager.h" @@ -28,6 +27,7 @@ #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/search_versus_navigate_classifier.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/spellcheck_host.h" #include "chrome/browser/spellchecker_platform_engine.h" @@ -445,10 +445,10 @@ void RenderViewContextMenu::AppendSearchProvider() { if (params_.selection_text.empty()) return; - AutocompleteMatch match; - profile_->GetAutocompleteClassifier()->Classify(params_.selection_text, - std::wstring(), &match, NULL); - selection_navigation_url_ = match.destination_url; + bool is_search; + profile_->GetSearchVersusNavigateClassifier()->Classify( + params_.selection_text, std::wstring(), &is_search, + &selection_navigation_url_, NULL, NULL, NULL); if (!selection_navigation_url_.is_valid()) return; @@ -458,14 +458,7 @@ void RenderViewContextMenu::AppendSearchProvider() { i = printable_selection_text.find('&', i + 2)) printable_selection_text.insert(i, 1, '&'); - if (match.transition == PageTransition::TYPED) { - if (ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme( - selection_navigation_url_.scheme())) { - AppendMenuItem(IDS_CONTENT_CONTEXT_GOTOURL, - l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL, - printable_selection_text)); - } - } else { + if (is_search) { const TemplateURL* const default_provider = profile_->GetTemplateURLModel()->GetDefaultSearchProvider(); if (!default_provider) @@ -474,6 +467,13 @@ void RenderViewContextMenu::AppendSearchProvider() { l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR, WideToUTF16(default_provider->short_name()), printable_selection_text)); + } else { + if (ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme( + selection_navigation_url_.scheme())) { + AppendMenuItem(IDS_CONTENT_CONTEXT_GOTOURL, + l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL, + printable_selection_text)); + } } } diff --git a/chrome/browser/theme_resources_util_unittest.cc b/chrome/browser/theme_resources_util_unittest.cc index 6153e75..4bd6bd0 100644 --- a/chrome/browser/theme_resources_util_unittest.cc +++ b/chrome/browser/theme_resources_util_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -20,7 +20,7 @@ TEST(ThemeResourcesUtil, SpotCheckIds) { const TestCase kTestCases[] = { {"back", IDR_BACK}, {"go", IDR_GO}, - {"omnibox_star", IDR_OMNIBOX_STAR}, + {"star", IDR_STAR}, {"sad_tab", IDR_SAD_TAB}, }; for (size_t i = 0; i < arraysize(kTestCases); ++i) { diff --git a/chrome/browser/toolbar_model.cc b/chrome/browser/toolbar_model.cc index c641539..c651e3d 100644 --- a/chrome/browser/toolbar_model.cc +++ b/chrome/browser/toolbar_model.cc @@ -17,7 +17,6 @@ #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "grit/generated_resources.h" -#include "grit/theme_resources.h" #include "net/base/cert_status_flags.h" #include "net/base/net_util.h" @@ -39,6 +38,7 @@ std::wstring ToolbarModel::GetText() const { languages = navigation_controller->profile()->GetPrefs()->GetString( prefs::kAcceptLanguages); NavigationEntry* entry = navigation_controller->GetActiveEntry(); + // We may not have a navigation entry yet if (!navigation_controller->tab_contents()->ShouldDisplayURL()) { // Explicitly hide the URL for this tab. url = GURL(); @@ -53,70 +53,144 @@ std::wstring ToolbarModel::GetText() const { url = GURL(url.scheme() + ":"); } } - return net::FormatUrl(url, languages, net::kFormatUrlOmitAll, - UnescapeRule::NORMAL, NULL, NULL, NULL); + return net::FormatUrl(url, languages, true, UnescapeRule::NORMAL, NULL, NULL, + NULL); } ToolbarModel::SecurityLevel ToolbarModel::GetSecurityLevel() const { if (input_in_progress_) // When editing, assume no security style. - return NONE; + return ToolbarModel::NORMAL; NavigationController* navigation_controller = GetNavigationController(); if (!navigation_controller) // We might not have a controller on init. - return NONE; + return ToolbarModel::NORMAL; NavigationEntry* entry = navigation_controller->GetActiveEntry(); if (!entry) - return NONE; + return ToolbarModel::NORMAL; - const NavigationEntry::SSLStatus& ssl = entry->ssl(); - switch (ssl.security_style()) { + switch (entry->ssl().security_style()) { + case SECURITY_STYLE_AUTHENTICATED: + if (entry->ssl().has_mixed_content()) + return ToolbarModel::NORMAL; + return ToolbarModel::SECURE; + case SECURITY_STYLE_AUTHENTICATION_BROKEN: + return ToolbarModel::INSECURE; case SECURITY_STYLE_UNKNOWN: case SECURITY_STYLE_UNAUTHENTICATED: - return NONE; + return ToolbarModel::NORMAL; + default: + NOTREACHED(); + return ToolbarModel::NORMAL; + } +} - case SECURITY_STYLE_AUTHENTICATION_BROKEN: - return SECURITY_ERROR; +ToolbarModel::SecurityLevel ToolbarModel::GetSchemeSecurityLevel() const { + // For now, in sync with the security level. + return GetSecurityLevel(); +} + +ToolbarModel::Icon ToolbarModel::GetIcon() const { + if (input_in_progress_) + return ToolbarModel::NO_ICON; + + NavigationController* navigation_controller = GetNavigationController(); + if (!navigation_controller) // We might not have a controller on init. + return ToolbarModel::NO_ICON; + NavigationEntry* entry = navigation_controller->GetActiveEntry(); + if (!entry) + return ToolbarModel::NO_ICON; + + const NavigationEntry::SSLStatus& ssl = entry->ssl(); + switch (ssl.security_style()) { case SECURITY_STYLE_AUTHENTICATED: if (ssl.has_mixed_content()) - return SECURITY_WARNING; - if (net::IsCertStatusError(ssl.cert_status())) { - DCHECK_EQ(ssl.cert_status() & net::CERT_STATUS_ALL_ERRORS, - net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION); - return SECURITY_WARNING; - } - if ((ssl.cert_status() & net::CERT_STATUS_IS_EV) && - CertStore::GetSharedInstance()->RetrieveCert(ssl.cert_id(), NULL)) - return EV_SECURE; - return SECURE; - + return ToolbarModel::WARNING_ICON; + return ToolbarModel::LOCK_ICON; + case SECURITY_STYLE_AUTHENTICATION_BROKEN: + return ToolbarModel::WARNING_ICON; + case SECURITY_STYLE_UNKNOWN: + case SECURITY_STYLE_UNAUTHENTICATED: + return ToolbarModel::NO_ICON; default: NOTREACHED(); - return NONE; + return ToolbarModel::NO_ICON; } } -int ToolbarModel::GetIcon() const { - static int icon_ids[NUM_SECURITY_LEVELS] = { - IDR_OMNIBOX_HTTP, - IDR_OMNIBOX_HTTPS_VALID, - IDR_OMNIBOX_HTTPS_VALID, - IDR_OMNIBOX_HTTPS_WARNING, - IDR_OMNIBOX_HTTPS_INVALID, - }; - DCHECK(arraysize(icon_ids) == NUM_SECURITY_LEVELS); - return icon_ids[GetSecurityLevel()]; +void ToolbarModel::GetIconHoverText(std::wstring* text) const { + DCHECK(text); + + NavigationController* navigation_controller = GetNavigationController(); + // We don't expect to be called during initialization, so the controller + // should never be NULL. + DCHECK(navigation_controller); + NavigationEntry* entry = navigation_controller->GetActiveEntry(); + DCHECK(entry); + + + const NavigationEntry::SSLStatus& ssl = entry->ssl(); + switch (ssl.security_style()) { + case SECURITY_STYLE_AUTHENTICATED: { + if (ssl.has_mixed_content()) { + SSLErrorInfo error_info = SSLErrorInfo::CreateError( + SSLErrorInfo::MIXED_CONTENTS, NULL, GURL()); + text->assign(error_info.short_description()); + } else { + DCHECK(entry->url().has_host()); + text->assign(l10n_util::GetStringF(IDS_SECURE_CONNECTION, + UTF8ToWide(entry->url().host()))); + } + break; + } + case SECURITY_STYLE_AUTHENTICATION_BROKEN: { + CreateErrorText(entry, text); + if (text->empty()) { + // If the authentication is broken, we should always have at least one + // error. + NOTREACHED(); + return; + } + break; + } + default: + // Don't show the info bubble in any other cases. + text->clear(); + break; + } } -std::wstring ToolbarModel::GetEVCertName() const { - DCHECK_EQ(GetSecurityLevel(), EV_SECURE); +ToolbarModel::InfoTextType ToolbarModel::GetInfoText( + std::wstring* text, + std::wstring* tooltip) const { + DCHECK(text && tooltip); + text->clear(); + tooltip->clear(); + + if (input_in_progress_) + return INFO_NO_INFO; + + NavigationController* navigation_controller = GetNavigationController(); + if (!navigation_controller) // We might not have a controller on init. + return INFO_NO_INFO; + + NavigationEntry* entry = navigation_controller->GetActiveEntry(); + const NavigationEntry::SSLStatus& ssl = entry->ssl(); + if (!entry || ssl.has_mixed_content() || + net::IsCertStatusError(ssl.cert_status()) || + ((ssl.cert_status() & net::CERT_STATUS_IS_EV) == 0)) + return INFO_NO_INFO; + scoped_refptr cert; - // Note: Navigation controller and active entry are guaranteed non-NULL or - // the security level would be NONE. - CertStore::GetSharedInstance()->RetrieveCert( - GetNavigationController()->GetActiveEntry()->ssl().cert_id(), &cert); - return SSLManager::GetEVCertName(*cert); + CertStore::GetSharedInstance()->RetrieveCert(ssl.cert_id(), &cert); + if (!cert.get()) { + NOTREACHED(); + return INFO_NO_INFO; + } + + SSLManager::GetEVCertNames(*cert, text, tooltip); + return INFO_EV_TEXT; } NavigationController* ToolbarModel::GetNavigationController() const { @@ -126,3 +200,37 @@ NavigationController* ToolbarModel::GetNavigationController() const { TabContents* current_tab = browser_->GetSelectedTabContents(); return current_tab ? ¤t_tab->controller() : NULL; } + +void ToolbarModel::CreateErrorText(NavigationEntry* entry, + std::wstring* text) const { + const NavigationEntry::SSLStatus& ssl = entry->ssl(); + std::vector errors; + SSLErrorInfo::GetErrorsForCertStatus(ssl.cert_id(), + ssl.cert_status(), + entry->url(), + &errors); + if (ssl.has_mixed_content()) { + errors.push_back(SSLErrorInfo::CreateError(SSLErrorInfo::MIXED_CONTENTS, + NULL, GURL())); + } + if (ssl.has_unsafe_content()) { + errors.push_back(SSLErrorInfo::CreateError(SSLErrorInfo::UNSAFE_CONTENTS, + NULL, GURL())); + } + + int error_count = static_cast(errors.size()); + if (error_count == 0) { + text->assign(L""); + } else if (error_count == 1) { + text->assign(errors[0].short_description()); + } else { + // Multiple errors. + text->assign(l10n_util::GetString(IDS_SEVERAL_SSL_ERRORS)); + text->append(L"\n"); + for (int i = 0; i < error_count; ++i) { + text->append(errors[i].short_description()); + if (i != error_count - 1) + text->append(L"\n"); + } + } +} diff --git a/chrome/browser/toolbar_model.h b/chrome/browser/toolbar_model.h index a4959e6fd..1d959c5 100644 --- a/chrome/browser/toolbar_model.h +++ b/chrome/browser/toolbar_model.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -18,36 +18,54 @@ class NavigationEntry; // from the navigation controller returned by GetNavigationController(). class ToolbarModel { public: - // TODO(wtc): unify ToolbarModel::SecurityLevel with SecurityStyle. We - // don't need two sets of security UI levels. SECURITY_STYLE_AUTHENTICATED - // needs to be refined into three levels: warning, standard, and EV. enum SecurityLevel { - NONE = 0, // HTTP/no URL/user is editing - EV_SECURE, // HTTPS with valid EV cert - SECURE, // HTTPS (non-EV) - SECURITY_WARNING, // HTTPS, but unable to check certificate revocation - // status or with mixed content on the page - SECURITY_ERROR, // Attempted HTTPS and failed, page not authenticated - NUM_SECURITY_LEVELS, + SECURE = 0, + NORMAL, + INSECURE + }; + + enum Icon { + NO_ICON = 0, + LOCK_ICON, + WARNING_ICON + }; + + enum InfoTextType { + INFO_NO_INFO = 0, + INFO_EV_TEXT, }; explicit ToolbarModel(Browser* browser); ~ToolbarModel(); // Returns the text that should be displayed in the location bar. + // Default value: empty string. std::wstring GetText() const; // Returns the security level that the toolbar should display. + // Default value: NORMAL. SecurityLevel GetSecurityLevel() const; - // Returns the resource_id of the icon to show to the left of the address, - // based on the current URL. This doesn't cover specialized icons while the - // user is editing; see AutocompleteEditView::GetIcon(). - int GetIcon() const; + // Returns the security level that should be used in the scheme part of the + // displayed URL. If SECURE, then the scheme is painted in green. If + // INSECURE, it is painted in red and stricken-out. + // Default value: NORMAL. + SecurityLevel GetSchemeSecurityLevel() const; - // Returns the name of the EV cert holder. Only call this when the security - // level is EV_SECURE. - std::wstring GetEVCertName() const; + // Returns the icon that should be displayed on the right of the location bar. + // Default value: NO_ICON. + Icon GetIcon() const; + + // Sets the text displayed in the info bubble that appears when the user + // hovers the mouse over the icon. + // Default value: empty string. + void GetIconHoverText(std::wstring* text) const; + + // Sets |text| to contain the text that should be displayed on the right of + // the location bar, and |tooltip| to the tooltip text that should be shown + // when the mouse hover over that info label. + // Default value: NO_INFO and empty string for |text| and |tooltip|. + InfoTextType GetInfoText(std::wstring* text, std::wstring* tooltip) const; // Getter/setter of whether the text in location bar is currently being // edited. @@ -60,6 +78,10 @@ class ToolbarModel { // If this returns NULL, default values are used. NavigationController* GetNavigationController() const; + // Builds a short error message from the SSL status code found in |entry|. + // The message is set in |text|. + void CreateErrorText(NavigationEntry* entry, std::wstring* text) const; + Browser* browser_; // Whether the text in the location bar is currently being edited. diff --git a/chrome/browser/views/accelerator_table_gtk.cc b/chrome/browser/views/accelerator_table_gtk.cc index 9e1f6c9..c8b54f7 100644 --- a/chrome/browser/views/accelerator_table_gtk.cc +++ b/chrome/browser/views/accelerator_table_gtk.cc @@ -115,6 +115,7 @@ const AcceleratorMapping kAcceleratorMap[] = { // Miscellany. { base::VKEY_D, false, true, false, IDC_BOOKMARK_PAGE }, { base::VKEY_D, true, true, false, IDC_BOOKMARK_ALL_TABS }, + { base::VKEY_B, false, true, false, IDC_SHOW_BOOKMARK_BAR }, { base::VKEY_DELETE, true, true, false, IDC_CLEAR_BROWSING_DATA }, { base::VKEY_H, false, true, false, IDC_SHOW_HISTORY }, { base::VKEY_J, false, true, false, IDC_SHOW_DOWNLOADS }, @@ -128,7 +129,7 @@ const AcceleratorMapping kAcceleratorMap[] = { { base::VKEY_F11, false, true, true, IDC_FULLSCREEN }, { base::VKEY_DELETE, false, true, true, IDC_TASK_MANAGER }, { base::VKEY_OEM_COMMA, false, true, false, IDC_SYSTEM_OPTIONS }, - { base::VKEY_B, true, true, false, IDC_SHOW_BOOKMARK_BAR }, + { base::VKEY_B, true, true, false, IDC_SHOW_BOOKMARK_MANAGER }, #if !defined(OS_CHROMEOS) { base::VKEY_F1, false, false, false, IDC_HELP_PAGE }, #endif diff --git a/chrome/browser/views/app_launcher.cc b/chrome/browser/views/app_launcher.cc index a074f84..d1e87aa 100644 --- a/chrome/browser/views/app_launcher.cc +++ b/chrome/browser/views/app_launcher.cc @@ -16,13 +16,12 @@ #include "chrome/browser/autocomplete/autocomplete_edit_view.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_window.h" +#include "chrome/browser/bubble_positioner.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/view_ids.h" #include "chrome/browser/views/dom_view.h" #include "chrome/browser/views/info_bubble.h" #include "chrome/browser/views/frame/browser_view.h" -#include "chrome/browser/views/toolbar_view.h" #include "chrome/common/url_constants.h" #include "views/widget/root_view.h" #include "views/widget/widget.h" @@ -46,11 +45,10 @@ const int kNavigationEntryYMargin = 1; // Padding between the navigation bar and the render view contents. const int kNavigationBarBottomPadding = 3; -// NavigationBar constants. -const int kNavigationBarHeight = 23; -const int kNavigationBarBorderThickness = 1; +// NavigationBar size. +const int kNavigationBarHeight = 25; -// The delta applied to the default font size for the Omnibox. +// The delta applied to the default font size for the omnibox. const int kAutocompleteEditFontDelta = 3; // Command line switch for specifying url of the page. @@ -74,7 +72,8 @@ static GURL GetMenuURL() { // mode. class NavigationBar : public views::View, - public AutocompleteEditController { + public AutocompleteEditController, + public BubblePositioner { public: explicit NavigationBar(AppLauncher* app_launcher) : app_launcher_(app_launcher), @@ -82,12 +81,7 @@ class NavigationBar : public views::View, SetFocusable(true); location_entry_view_ = new views::NativeViewHost; AddChildView(location_entry_view_); - set_border(views::Border::CreateSolidBorder(kNavigationBarBorderThickness, - SK_ColorGRAY)); - - AddChildView(&popup_positioning_view_); - popup_positioning_view_.SetVisible(false); - popup_positioning_view_.set_parent_owned(false); + set_border(views::Border::CreateSolidBorder(1, SK_ColorGRAY)); } virtual ~NavigationBar() { @@ -117,8 +111,7 @@ class NavigationBar : public views::View, new AutocompleteEditViewWin(font, this, browser->toolbar_model(), this, GetWidget()->GetNativeView(), browser->profile(), - browser->command_updater(), false, - &popup_positioning_view_); + browser->command_updater(), false, this); location_entry_.reset(autocomplete_view); autocomplete_view->Update(NULL); // The Update call above sets the autocomplete text to the current one in @@ -128,11 +121,10 @@ class NavigationBar : public views::View, AutocompleteEditViewGtk* autocomplete_view = new AutocompleteEditViewGtk(this, browser->toolbar_model(), browser->profile(), - browser->command_updater(), false, - &popup_positioning_view_); + browser->command_updater(), false, this); autocomplete_view->Init(); - gtk_widget_show_all(autocomplete_view->GetNativeView()); - gtk_widget_hide(autocomplete_view->GetNativeView()); + gtk_widget_show_all(autocomplete_view->widget()); + gtk_widget_hide(autocomplete_view->widget()); location_entry_.reset(autocomplete_view); #else NOTIMPLEMENTED(); @@ -149,10 +141,21 @@ class NavigationBar : public views::View, bounds.width() - 2 * (kNavigationEntryPadding + kNavigationEntryXMargin), bounds.height() - kNavigationEntryYMargin * 2); + } - gfx::Rect popup_positioning_bounds(bounds); - popup_positioning_bounds.Inset(0, -(kNavigationBarBorderThickness + 1)); - popup_positioning_view_.SetBounds(popup_positioning_bounds); + // BubblePositioner implementation. + virtual gfx::Rect GetLocationStackBounds() const { + gfx::Rect bounds = location_entry_view_->GetBounds( + views::View::APPLY_MIRRORING_TRANSFORMATION); + gfx::Point origin(bounds.x(), bounds.bottom() + kNavigationEntryPadding); + views::View::ConvertPointToScreen(this, &origin); + gfx::Rect rect = gfx::Rect(origin, gfx::Size(500, 0)); + if (UILayoutIsRightToLeft()) { + // Align the window to the right side of the entry view when + // UI is RTL mode. + rect.set_x(rect.x() - (rect.width() - location_entry_view_->width())); + } + return rect; } // AutocompleteController implementation. @@ -192,11 +195,6 @@ class NavigationBar : public views::View, NOTIMPLEMENTED(); #endif - // This invisible view is provided to the popup in place of |this|, so the - // popup can size itself against it using the same offsets it does with the - // LocationBarView. - views::View popup_positioning_view_; - DISALLOW_COPY_AND_ASSIGN(NavigationBar); }; @@ -239,7 +237,6 @@ InfoBubbleContentsView::InfoBubbleContentsView(AppLauncher* app_launcher) : app_launcher_(app_launcher), navigation_bar_(NULL), dom_view_(NULL) { - DCHECK(app_launcher); } InfoBubbleContentsView::~InfoBubbleContentsView() { @@ -302,7 +299,6 @@ void InfoBubbleContentsView::Layout() { AppLauncher::AppLauncher(Browser* browser) : browser_(browser), info_bubble_(NULL) { - DCHECK(browser); info_bubble_content_ = new InfoBubbleContentsView(this); } @@ -310,15 +306,12 @@ AppLauncher::~AppLauncher() { } // static -AppLauncher* AppLauncher::Show(Browser* browser, - const gfx::Rect& bounds, - const gfx::Point& bubble_anchor) { +AppLauncher* AppLauncher::Show(Browser* browser, const gfx::Rect& bounds) { AppLauncher* app_launcher = new AppLauncher(browser); BrowserView* browser_view = static_cast(browser->window()); app_launcher->info_bubble_ = - PinnedContentsInfoBubble::Show(browser_view->frame()->GetWindow(), - bounds, bubble_anchor, app_launcher->info_bubble_content_, - app_launcher); + InfoBubble::Show(browser_view->frame()->GetWindow(), bounds, + app_launcher->info_bubble_content_, app_launcher); app_launcher->info_bubble_content_->BubbleShown(); return app_launcher; } @@ -333,17 +326,7 @@ AppLauncher* AppLauncher::ShowForNewTab(Browser* browser) { gfx::Point origin = bounds.origin(); views::RootView::ConvertPointToScreen(tabstrip, &origin); bounds.set_origin(origin); - - // Figure out where the location bar is, so we can pin the bubble to - // make our url bar appear exactly over it. - views::RootView* root_view = views::Widget::GetWidgetFromNativeWindow( - browser_view->GetNativeHandle())->GetRootView(); - views::View* location_bar = root_view->GetViewByID(VIEW_ID_LOCATION_BAR); - gfx::Point location_bar_origin = location_bar->bounds().origin(); - views::RootView::ConvertPointToScreen(location_bar->GetParent(), - &location_bar_origin); - - return Show(browser, bounds, location_bar_origin); + return Show(browser, bounds); } void AppLauncher::Hide() { @@ -369,6 +352,7 @@ void AppLauncher::InfoBubbleClosing(InfoBubble* info_bubble, new DeleteTask(this)); } + void AppLauncher::AddTabWithURL(const GURL& url, PageTransition::Type transition) { #if defined(OS_CHROMEOS) diff --git a/chrome/browser/views/app_launcher.h b/chrome/browser/views/app_launcher.h index fa5cc03..229f265 100644 --- a/chrome/browser/views/app_launcher.h +++ b/chrome/browser/views/app_launcher.h @@ -7,7 +7,7 @@ #include "base/scoped_ptr.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" -#include "chrome/browser/views/pinned_contents_info_bubble.h" +#include "chrome/browser/views/info_bubble.h" #include "views/view.h" class Browser; @@ -49,17 +49,13 @@ class TabContentsDelegateImpl; // When a new url is opened, or the user clicks outsides the bounds of the // widget the app launcher is closed. class AppLauncher : public InfoBubbleDelegate, - public TabContentsDelegate { + public TabContentsDelegate { public: // Shows an application launcher bubble pointing to the |bounds| (which should - // be in screen coordinates). |bubble_anchor| specifies at which coordinates - // the bubble contents should appear (in screen coordinates). The bubble will - // be moved accordingly. + // be in screen coordinates). // The caller DOES NOT OWN the AppLauncher returned. It is deleted // automatically when the AppLauncher is closed. - static AppLauncher* Show(Browser* browser, - const gfx::Rect& bounds, - const gfx::Point& bubble_anchor); + static AppLauncher* Show(Browser* browser, const gfx::Rect& bounds); // Shows an application launcher bubble pointing to the new tab button. // The caller DOES NOT OWN the AppLauncher returned. It is deleted @@ -111,8 +107,8 @@ class AppLauncher : public InfoBubbleDelegate, // The currently active browser. We use this to open urls. Browser* browser_; - // The InfoBubble displaying the Omnibox and app contents. - PinnedContentsInfoBubble* info_bubble_; + // The InfoBubble displaying the omnibox and app contents. + InfoBubble* info_bubble_; // The view with the navigation bar and render view, shown in the info-bubble. InfoBubbleContentsView* info_bubble_content_; diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc index de0464e..d5eb1f3 100644 --- a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc +++ b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc @@ -12,6 +12,7 @@ #include "base/i18n/rtl.h" #include "chrome/browser/autocomplete/autocomplete_edit_view.h" #include "chrome/browser/autocomplete/autocomplete_popup_model.h" +#include "chrome/browser/bubble_positioner.h" #include "chrome/browser/views/bubble_border.h" #include "gfx/canvas.h" #include "gfx/color_utils.h" @@ -90,8 +91,13 @@ const int kIconVerticalPadding = 2; // bottom of the row. See comment about the use of "minimum" for // kIconVerticalPadding. const int kTextVerticalPadding = 3; -// The padding between horizontally adjacent items (including row edges). -const int kHorizontalPadding = 3; +// The padding at the left edge of the row, left of the icon. +const int kRowLeftPadding = 6; +// The padding on the right edge of the row, right of the text. +const int kRowRightPadding = 3; +// The horizontal distance between the right edge of the icon and the left edge +// of the text. +const int kIconTextSpacing = 9; // The size delta between the font used for the edit and the result rows. Passed // to gfx::Font::DeriveFont. #if !defined(OS_CHROMEOS) @@ -164,15 +170,40 @@ class AutocompleteResultView : public views::View { gfx::Rect icon_bounds_; gfx::Rect text_bounds_; + // Icons for rows. + static SkBitmap* icon_url_; + static SkBitmap* icon_url_selected_; + static SkBitmap* icon_history_; + static SkBitmap* icon_history_selected_; + static SkBitmap* icon_search_; + static SkBitmap* icon_search_selected_; + static SkBitmap* icon_more_; + static SkBitmap* icon_more_selected_; + static SkBitmap* icon_star_; + static SkBitmap* icon_star_selected_; static int icon_size_; AutocompleteMatch match_; + static bool initialized_; + static void InitClass(); + DISALLOW_COPY_AND_ASSIGN(AutocompleteResultView); }; // static +SkBitmap* AutocompleteResultView::icon_url_ = NULL; +SkBitmap* AutocompleteResultView::icon_url_selected_ = NULL; +SkBitmap* AutocompleteResultView::icon_history_ = NULL; +SkBitmap* AutocompleteResultView::icon_history_selected_ = NULL; +SkBitmap* AutocompleteResultView::icon_search_ = NULL; +SkBitmap* AutocompleteResultView::icon_search_selected_ = NULL; +SkBitmap* AutocompleteResultView::icon_star_ = NULL; +SkBitmap* AutocompleteResultView::icon_star_selected_ = NULL; +SkBitmap* AutocompleteResultView::icon_more_ = NULL; +SkBitmap* AutocompleteResultView::icon_more_selected_ = NULL; int AutocompleteResultView::icon_size_ = 0; +bool AutocompleteResultView::initialized_ = false; // This class is a utility class which mirrors an x position, calculates the // index of the i-th run of a text, and calculates the index of the i-th @@ -291,11 +322,7 @@ AutocompleteResultView::AutocompleteResultView( mirroring_context_(new MirroringContext()), match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED) { CHECK(model_index >= 0); - if (icon_size_ == 0) { - icon_size_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( - AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))-> - width(); - } + InitClass(); } AutocompleteResultView::~AutocompleteResultView() { @@ -317,8 +344,7 @@ void AutocompleteResultView::Paint(gfx::Canvas* canvas) { // position of an input text. bool text_mirroring = View::UILayoutIsRightToLeft(); int text_left = MirroredLeftPointForRect(text_bounds_); - int text_right = - text_mirroring ? (x - kHorizontalPadding) : text_bounds_.right(); + int text_right = text_mirroring ? x - kIconTextSpacing : text_bounds_.right(); x = mirroring_context_->Initialize(text_left, text_right, text_mirroring); x = DrawString(canvas, match_.contents, match_.contents_class, false, x, text_bounds_.y()); @@ -339,11 +365,13 @@ void AutocompleteResultView::Paint(gfx::Canvas* canvas) { } void AutocompleteResultView::Layout() { - icon_bounds_.SetRect(kHorizontalPadding, (height() - icon_size_) / 2, + icon_bounds_.SetRect(kRowLeftPadding, (height() - icon_size_) / 2, icon_size_, icon_size_); - int text_x = icon_bounds_.right() + kHorizontalPadding; - text_bounds_.SetRect(text_x, std::max(0, (height() - font_.height()) / 2), - std::max(0, bounds().right() - text_x - kHorizontalPadding), + int text_x = icon_bounds_.right() + kIconTextSpacing; + text_bounds_.SetRect( + text_x, + std::max(0, (height() - font_.height()) / 2), + std::max(0, bounds().right() - text_x - kRowRightPadding), font_.height()); } @@ -361,19 +389,29 @@ ResultViewState AutocompleteResultView::GetState() const { } SkBitmap* AutocompleteResultView::GetIcon() const { - int icon = match_.starred ? - IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type); - if (model_->IsSelectedIndex(model_index_)) { - switch (icon) { - case IDR_OMNIBOX_HTTP: icon = IDR_OMNIBOX_HTTP_SELECTED; break; - case IDR_OMNIBOX_HISTORY: icon = IDR_OMNIBOX_HISTORY_SELECTED; break; - case IDR_OMNIBOX_SEARCH: icon = IDR_OMNIBOX_SEARCH_SELECTED; break; - case IDR_OMNIBOX_MORE: icon = IDR_OMNIBOX_MORE_SELECTED; break; - case IDR_OMNIBOX_STAR: icon = IDR_OMNIBOX_STAR_SELECTED; break; - default: NOTREACHED(); break; - } + bool selected = model_->IsSelectedIndex(model_index_); + if (match_.starred) + return selected ? icon_star_selected_ : icon_star_; + switch (match_.type) { + case AutocompleteMatch::URL_WHAT_YOU_TYPED: + case AutocompleteMatch::HISTORY_URL: + case AutocompleteMatch::NAVSUGGEST: + return selected ? icon_url_selected_ : icon_url_; + case AutocompleteMatch::HISTORY_TITLE: + case AutocompleteMatch::HISTORY_BODY: + case AutocompleteMatch::HISTORY_KEYWORD: + return selected ? icon_history_selected_ : icon_history_; + case AutocompleteMatch::SEARCH_WHAT_YOU_TYPED: + case AutocompleteMatch::SEARCH_HISTORY: + case AutocompleteMatch::SEARCH_SUGGEST: + case AutocompleteMatch::SEARCH_OTHER_ENGINE: + return selected ? icon_search_selected_ : icon_search_; + case AutocompleteMatch::OPEN_HISTORY_PAGE: + return selected ? icon_more_selected_ : icon_more_; + default: + NOTREACHED(); + return NULL; } - return ResourceBundle::GetSharedInstance().GetBitmapNamed(icon); } int AutocompleteResultView::DrawString( @@ -470,7 +508,7 @@ int AutocompleteResultView::DrawStringFragment( // Clamp text width to the available width within the popup so we elide if // necessary. int string_width = std::min(display_font.GetStringWidth(text), - width() - kHorizontalPadding - x); + width() - kRowRightPadding - x); int string_left = mirroring_context_->GetLeft(x, x + string_width); const int flags = force_rtl_directionality ? gfx::Canvas::FORCE_RTL_DIRECTIONALITY : 0; @@ -493,6 +531,25 @@ SkColor AutocompleteResultView::GetFragmentTextColor(int style) const { (style & ACMatchClassification::DIM) ? DIMMED_TEXT : TEXT); } +void AutocompleteResultView::InitClass() { + if (!initialized_) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + icon_url_ = rb.GetBitmapNamed(IDR_O2_GLOBE); + icon_url_selected_ = rb.GetBitmapNamed(IDR_O2_GLOBE_SELECTED); + icon_history_ = rb.GetBitmapNamed(IDR_O2_HISTORY); + icon_history_selected_ = rb.GetBitmapNamed(IDR_O2_HISTORY_SELECTED); + icon_search_ = rb.GetBitmapNamed(IDR_O2_SEARCH); + icon_search_selected_ = rb.GetBitmapNamed(IDR_O2_SEARCH_SELECTED); + icon_star_ = rb.GetBitmapNamed(IDR_O2_STAR); + icon_star_selected_ = rb.GetBitmapNamed(IDR_O2_STAR_SELECTED); + icon_more_ = rb.GetBitmapNamed(IDR_O2_MORE); + icon_more_selected_ = rb.GetBitmapNamed(IDR_O2_MORE_SELECTED); + // All icons are assumed to be square, and the same size. + icon_size_ = icon_url_->width(); + initialized_ = true; + } +} + //////////////////////////////////////////////////////////////////////////////// // AutocompletePopupContentsView, public: @@ -501,10 +558,10 @@ AutocompletePopupContentsView::AutocompletePopupContentsView( AutocompleteEditView* edit_view, AutocompleteEditModel* edit_model, Profile* profile, - const views::View* location_bar) + const BubblePositioner* bubble_positioner) : model_(new AutocompletePopupModel(this, edit_model, profile)), edit_view_(edit_view), - location_bar_(location_bar), + bubble_positioner_(bubble_positioner), result_font_(font.DeriveFont(kEditFontAdjust)), ignore_mouse_drag_(false), ALLOW_THIS_IN_INITIALIZER_LIST(size_animation_(this)) { @@ -580,13 +637,10 @@ void AutocompletePopupContentsView::UpdatePopupAppearance() { } // Calculate desired bounds. - gfx::Rect location_bar_bounds(location_bar_->bounds()); - gfx::Point location; - views::View::ConvertPointToScreen(location_bar_, &location); - location_bar_bounds.set_origin(location); - location_bar_bounds.set_height(location_bar_bounds.height() - 1); - gfx::Rect new_target_bounds(bubble_border_->GetBounds(location_bar_bounds, - gfx::Size(location_bar_bounds.width(), total_child_height))); + gfx::Rect location_stack_bounds = + bubble_positioner_->GetLocationStackBounds(); + gfx::Rect new_target_bounds(bubble_border_->GetBounds(location_stack_bounds, + gfx::Size(location_stack_bounds.width(), total_child_height))); // If we're animating and our target height changes, reset the animation. // NOTE: If we just reset blindly on _every_ update, then when the user types @@ -793,19 +847,7 @@ void AutocompletePopupContentsView::MakeContentsPath( SkIntToScalar(bounding_rect.bottom())); SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius()); - SkScalar scaled_radius = - SkScalarMul(radius, (SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3); - path->moveTo(rect.fRight, rect.fTop); - path->lineTo(rect.fRight, rect.fBottom - radius); - path->cubicTo(rect.fRight, rect.fBottom - radius + scaled_radius, - rect.fRight - radius + scaled_radius, rect.fBottom, - rect.fRight - radius, rect.fBottom); - path->lineTo(rect.fLeft + radius, rect.fBottom); - path->cubicTo(rect.fLeft + radius - scaled_radius, rect.fBottom, - rect.fLeft, rect.fBottom - radius + scaled_radius, - rect.fLeft, rect.fBottom - radius); - path->lineTo(rect.fLeft, rect.fTop); - path->close(); + path->addRoundRect(rect, radius, radius); } void AutocompletePopupContentsView::UpdateBlurRegion() { @@ -878,3 +920,14 @@ size_t AutocompletePopupContentsView::GetIndexForPoint( } return AutocompletePopupModel::kNoMatch; } + +// static +AutocompletePopupView* AutocompletePopupView::CreatePopupView( + const gfx::Font& font, + AutocompleteEditView* edit_view, + AutocompleteEditModel* edit_model, + Profile* profile, + const BubblePositioner* bubble_positioner) { + return new AutocompletePopupContentsView(font, edit_view, edit_model, + profile, bubble_positioner); +} diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h index d814206..30a9bf1 100644 --- a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h +++ b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h @@ -45,7 +45,7 @@ class AutocompletePopupContentsView : public views::View, AutocompleteEditView* edit_view, AutocompleteEditModel* edit_model, Profile* profile, - const views::View* location_bar); + const BubblePositioner* bubble_positioner); virtual ~AutocompletePopupContentsView(); // Returns the bounds the popup should be shown at. This is the display bounds @@ -125,8 +125,8 @@ class AutocompletePopupContentsView : public views::View, // The edit view that invokes us. AutocompleteEditView* edit_view_; - // An object that the popup positions itself against. - const views::View* location_bar_; + // An object that tells the popup how to position itself. + const BubblePositioner* bubble_positioner_; // Our border, which can compute our desired bounds. const BubbleBorder* bubble_border_; diff --git a/chrome/browser/views/bookmark_editor_view.cc b/chrome/browser/views/bookmark_editor_view.cc index bd61ab3..34f8e91 100644 --- a/chrome/browser/views/bookmark_editor_view.cc +++ b/chrome/browser/views/bookmark_editor_view.cc @@ -282,9 +282,10 @@ void BookmarkEditorView::Init() { std::wstring languages = profile_ ? profile_->GetPrefs()->GetString(prefs::kAcceptLanguages) : std::wstring(); - // The following URL is user-editable, so we don't strip anything from it. + // The following URL is user-editable. We specify omit_username_password= + // false and unescape=false to show the original URL except IDN. url_text = net::FormatUrl(details_.existing_node->GetURL(), languages, - net::kFormatUrlOmitNothing, UnescapeRule::NONE, NULL, NULL, NULL); + false, UnescapeRule::NONE, NULL, NULL, NULL); } url_tf_.SetText(url_text); url_tf_.SetController(this); diff --git a/chrome/browser/views/browser_views_accessibility_browsertest.cc b/chrome/browser/views/browser_views_accessibility_browsertest.cc index 6a5bcf1..ac20277 100644 --- a/chrome/browser/views/browser_views_accessibility_browsertest.cc +++ b/chrome/browser/views/browser_views_accessibility_browsertest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -218,8 +218,7 @@ IN_PROC_BROWSER_TEST_F(BrowserViewsAccessibilityTest, TestHomeButtonAccObj) { } // Retrieve accessibility object for Star button and verify accessibility info. -IN_PROC_BROWSER_TEST_F(BrowserViewsAccessibilityTest, - TestStarButtonAccObj) { +IN_PROC_BROWSER_TEST_F(BrowserViewsAccessibilityTest, TestStarButtonAccObj) { // Verify Star button MSAA name and role. TestViewAccessibilityObject( GetToolbarView()->GetViewByID(VIEW_ID_STAR_BUTTON), diff --git a/chrome/browser/views/bubble_border.cc b/chrome/browser/views/bubble_border.cc index 3548286..230a0f4 100644 --- a/chrome/browser/views/bubble_border.cc +++ b/chrome/browser/views/bubble_border.cc @@ -1,6 +1,6 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in the +// LICENSE file. #include "chrome/browser/views/bubble_border.h" @@ -31,6 +31,10 @@ static const int kArrowInteriorHeight = 7; gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to, const gfx::Size& contents_size) const { + // The spacing (in pixels) between |position_relative_to| and the bubble + // content. + const int kBubbleSpacing = 2; + // Desired size is size of contents enlarged by the size of the border images. gfx::Size border_size(contents_size); gfx::Insets insets; @@ -39,40 +43,33 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to, insets.top() + insets.bottom()); // Screen position depends on the arrow location. - // The arrow should overlap the target by some amount since the bottom arrow - // has lots of shadow below it and the top arrow is given an equivalent amount - // of padding. - const int kArrowOverlap = 3; int x = position_relative_to.x() + (position_relative_to.width() / 2); - int arrow_offset = override_arrow_x_offset_ ? override_arrow_x_offset_ : - arrow_x_offset_; if (arrow_is_left()) - x -= arrow_offset; + x -= arrow_x_offset_; else if (arrow_location_ == NONE) x -= ((contents_size.width() / 2) + insets.left()); else - x += (arrow_offset - border_size.width() + 1); + x += (arrow_x_offset_ - border_size.width() + 1); int y = position_relative_to.y(); - if (arrow_is_bottom()) - y += (kArrowOverlap - border_size.height()); - else if (arrow_location_ == NONE) - y += position_relative_to.height(); - else - y += (position_relative_to.height() - kArrowOverlap); + if (arrow_is_top()) { + y += (position_relative_to.height() - + (top_arrow_->height() - kBubbleSpacing)); + } else if (arrow_location_ == NONE) { + y += (position_relative_to.height() - (top_->height() - kBubbleSpacing)); + } else { + y += ((bottom_arrow_->height() - kBubbleSpacing) - border_size.height()); + } return gfx::Rect(x, y, border_size.width(), border_size.height()); } void BubbleBorder::GetInsets(gfx::Insets* insets) const { - int top, bottom; - if (arrow_is_bottom()) { - top = top_->height(); - bottom = std::max(bottom_->height(), bottom_arrow_->height()); - } else { - top = (arrow_location_ == NONE) ? - 0 : std::max(top_->height(), top_arrow_->height()); - bottom = bottom_->height(); - } + int top = top_->height(); + int bottom = bottom_->height(); + if (arrow_is_top()) + top = std::max(top, top_arrow_->height()); + else if (arrow_location_ != NONE) + bottom = std::max(bottom, bottom_arrow_->height()); insets->Set(top, left_->width(), bottom, right_->width()); } @@ -105,7 +102,7 @@ void BubbleBorder::InitClass() { } void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { - // Convenience shorthand variables. + // Convenience shorthand variables int width = view.width(); int tl_width = top_left_->width(); int tl_height = top_left_->height(); @@ -135,33 +132,25 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { * border_bottom∙∙∙∙└────┴─┤ â–¼ ├──────┤ â–¼ ├─┴────┘ * view.height()∙∙∙∙∙∙∙∙∙∙∙└───┘ └───┘ * - * If |arrow_location_| == NONE, the entire top edge is ommitted, and - * |tl_bottom| == |tr_bottom| == 0. Otherwise, one of the four arrows will be - * drawn. + * (At most one of the arrows will be drawn) */ gfx::Insets insets; GetInsets(&insets); int top = insets.top(); + int border_top = top - t_height; + int tl_bottom = border_top + tl_height; + int tr_bottom = border_top + tr_height; int bottom = view.height() - insets.bottom(); int border_bottom = bottom + b_height; int bl_y = border_bottom - bl_height; int br_y = border_bottom - br_height; - int border_top, tl_bottom, tr_bottom; - if (arrow_location_ == NONE) { - border_top = tl_bottom = tr_bottom = 0; - } else { - border_top = top - t_height; - tl_bottom = border_top + tl_height; - tr_bottom = border_top + tr_height; - - // Top left corner - canvas->DrawBitmapInt(*top_left_, 0, border_top); + // Top left corner + canvas->DrawBitmapInt(*top_left_, 0, border_top); - // Top right corner - canvas->DrawBitmapInt(*top_right_, width - tr_width, border_top); - } + // Top right corner + canvas->DrawBitmapInt(*top_right_, width - tr_width, border_top); // Right edge canvas->TileImageInt(*right_, width - r_width, tr_bottom, r_width, @@ -178,7 +167,7 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { canvas->TileImageInt(*left_, 0, tl_bottom, left_->width(), bl_y - tl_bottom); // Arrow edge, if necessary - bool should_draw_top_edge = false; + bool should_draw_top_edge = true; bool should_draw_bottom_edge = true; if (arrow_location_ != NONE) { /* Here's what the variables below mean (without loss of generality): @@ -205,17 +194,8 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { SkBitmap* arrow; int left_of_edge, right_of_edge, edge_y, arrow_y; SkScalar border_y, tip_y; - if (arrow_is_bottom()) { - should_draw_top_edge = true; - should_draw_bottom_edge = false; - edge = bottom_; - arrow = bottom_arrow_; - left_of_edge = bl_width; - right_of_edge = br_width; - edge_y = arrow_y = bottom; - border_y = SkIntToScalar(bottom); - tip_y = SkIntToScalar(bottom + kArrowInteriorHeight); - } else { + if (arrow_is_top()) { + should_draw_top_edge = false; edge = top_; arrow = top_arrow_; left_of_edge = tl_width; @@ -224,12 +204,19 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { arrow_y = top - top_arrow_->height(); border_y = SkIntToScalar(top); tip_y = SkIntToScalar(top - kArrowInteriorHeight); + } else { + should_draw_bottom_edge = false; + edge = bottom_; + arrow = bottom_arrow_; + left_of_edge = bl_width; + right_of_edge = br_width; + edge_y = arrow_y = bottom; + border_y = SkIntToScalar(bottom); + tip_y = SkIntToScalar(bottom + kArrowInteriorHeight); } - int arrow_offset = override_arrow_x_offset_ ? override_arrow_x_offset_ : - arrow_x_offset_; - int arrow_width = arrow->width(); + int arrow_width = (arrow_is_top() ? top_arrow_ : bottom_arrow_)->width(); int arrow_center = arrow_is_left() ? - arrow_offset : width - arrow_offset - 1; + arrow_x_offset_ : width - arrow_x_offset_ - 1; int arrow_x = arrow_center - (arrow_width / 2); SkScalar arrow_interior_x = SkIntToScalar(arrow_center - kArrowInteriorHeight); @@ -284,8 +271,6 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const { // The border of this view creates an anti-aliased round-rect region for the // contents, which we need to fill with the background color. - // NOTE: This doesn't handle an arrow location of "NONE", which has square top - // corners. SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kFill_Style); diff --git a/chrome/browser/views/bubble_border.h b/chrome/browser/views/bubble_border.h index 3670503..3b48048 100644 --- a/chrome/browser/views/bubble_border.h +++ b/chrome/browser/views/bubble_border.h @@ -1,6 +1,6 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in the +// LICENSE file. #ifndef CHROME_BROWSER_VIEWS_BUBBLE_BORDER_H_ #define CHROME_BROWSER_VIEWS_BUBBLE_BORDER_H_ @@ -11,11 +11,8 @@ class SkBitmap; -// Renders a border, with optional arrow (off by default), and a custom -// dropshadow. This can be used to produce floating "bubble" objects. -// -// If the arrow is on, the bubble has four round corner. If not, it has round -// corners on the bottom and square corners on the top, and lacks a top border. +// Renders a round-rect border, with optional arrow (off by default), and a +// custom dropshadow. This can be used to produce floating "bubble" objects. class BubbleBorder : public views::Border { public: // Possible locations for the (optional) arrow. @@ -27,9 +24,7 @@ class BubbleBorder : public views::Border { BOTTOM_RIGHT }; - BubbleBorder() : override_arrow_x_offset_(0), - arrow_location_(NONE), - background_color_(SK_ColorWHITE) { + BubbleBorder() : arrow_location_(NONE), background_color_(SK_ColorWHITE) { InitClass(); } @@ -47,12 +42,6 @@ class BubbleBorder : public views::Border { arrow_location_ = arrow_location; } - // Sets a fixed x offset for the arrow. The arrow will still point to the - // same location but the bubble will shift horizontally to make that happen. - void set_arrow_offset(int offset) { - override_arrow_x_offset_ = offset; - } - // Sets the background color for the arrow body. This is irrelevant if you do // not also set the arrow location to something other than NONE. void set_background_color(SkColor background_color) { @@ -79,10 +68,9 @@ class BubbleBorder : public views::Border { virtual ~BubbleBorder() { } - // Returns true if there is an arrow and it is positioned on the bottom edge. - bool arrow_is_bottom() const { - return (arrow_location_ == BOTTOM_LEFT) || - (arrow_location_ == BOTTOM_RIGHT); + // Returns true if there is an arrow and it is positioned on the top edge. + bool arrow_is_top() const { + return (arrow_location_ == TOP_LEFT) || (arrow_location_ == TOP_RIGHT); } // Returns true if there is an arrow and it is positioned on the left side. @@ -107,9 +95,6 @@ class BubbleBorder : public views::Border { static int arrow_x_offset_; - // If specified, overrides the pre-calculated |arrow_x_offset_| of the arrow. - int override_arrow_x_offset_; - ArrowLocation arrow_location_; SkColor background_color_; diff --git a/chrome/browser/views/constrained_window_win.cc b/chrome/browser/views/constrained_window_win.cc index c70ec75..488f1a4 100644 --- a/chrome/browser/views/constrained_window_win.cc +++ b/chrome/browser/views/constrained_window_win.cc @@ -34,7 +34,6 @@ #include "views/window/client_view.h" #include "views/window/non_client_view.h" #include "views/window/window_resources.h" -#include "views/window/window_shape.h" using base::TimeDelta; @@ -350,7 +349,24 @@ int ConstrainedWindowFrameView::NonClientHitTest(const gfx::Point& point) { void ConstrainedWindowFrameView::GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) { DCHECK(window_mask); - views::GetDefaultWindowMask(size, window_mask); + + // Redefine the window visible region for the new size. + window_mask->moveTo(0, 3); + window_mask->lineTo(1, 2); + window_mask->lineTo(1, 1); + window_mask->lineTo(2, 1); + window_mask->lineTo(3, 0); + + window_mask->lineTo(SkIntToScalar(size.width() - 3), 0); + window_mask->lineTo(SkIntToScalar(size.width() - 2), 1); + window_mask->lineTo(SkIntToScalar(size.width() - 1), 1); + window_mask->lineTo(SkIntToScalar(size.width() - 1), 2); + window_mask->lineTo(SkIntToScalar(size.width()), 3); + + window_mask->lineTo(SkIntToScalar(size.width()), + SkIntToScalar(size.height())); + window_mask->lineTo(0, SkIntToScalar(size.height())); + window_mask->close(); } void ConstrainedWindowFrameView::EnableClose(bool enable) { diff --git a/chrome/browser/views/frame/browser_frame_win.cc b/chrome/browser/views/frame/browser_frame_win.cc index 0092fa7..d12963f 100644 --- a/chrome/browser/views/frame/browser_frame_win.cc +++ b/chrome/browser/views/frame/browser_frame_win.cc @@ -28,9 +28,6 @@ // static static const int kClientEdgeThickness = 3; static const int kTabDragWindowAlpha = 200; -// We need to offset the DWMFrame into the toolbar so that the blackness -// doesn't show up on our rounded corners. -static const int kDWMFrameTopOffset = 3; // static (Factory method.) BrowserFrame* BrowserFrame::Create(BrowserView* browser_view, @@ -306,8 +303,7 @@ void BrowserFrameWin::UpdateDWMFrame() { margins.cyTopHeight += GetSystemMetrics(SM_CYSIZEFRAME); } else { margins.cyTopHeight = - GetBoundsForTabStrip(browser_view_->tabstrip()).bottom() + - kDWMFrameTopOffset; + GetBoundsForTabStrip(browser_view_->tabstrip()).bottom(); } } } else { diff --git a/chrome/browser/views/frame/browser_root_view.cc b/chrome/browser/views/frame/browser_root_view.cc index d2985dd..d789b94 100644 --- a/chrome/browser/views/frame/browser_root_view.cc +++ b/chrome/browser/views/frame/browser_root_view.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,10 +7,9 @@ #include "app/drag_drop_types.h" #include "app/l10n_util.h" #include "app/os_exchange_data.h" -#include "chrome/browser/autocomplete/autocomplete.h" -#include "chrome/browser/autocomplete/autocomplete_classifier.h" #include "chrome/browser/location_bar.h" #include "chrome/browser/profile.h" +#include "chrome/browser/search_versus_navigate_classifier.h" #include "chrome/browser/views/frame/browser_view.h" #include "chrome/browser/views/frame/browser_frame.h" #include "chrome/browser/views/tabs/tab_strip.h" @@ -142,13 +141,13 @@ bool BrowserRootView::GetPasteAndGoURL(const OSExchangeData& data, GURL* url) { if (!data.GetString(&text) || text.empty()) return false; - AutocompleteMatch match; - browser_view_->browser()->profile()->GetAutocompleteClassifier()->Classify( - text, std::wstring(), &match, NULL); - if (!match.destination_url.is_valid()) + GURL destination_url; + browser_view_->browser()->profile()->GetSearchVersusNavigateClassifier()-> + Classify(text, std::wstring(), NULL, &destination_url, NULL, NULL, NULL); + if (!destination_url.is_valid()) return false; if (url) - *url = match.destination_url; + *url = destination_url; return true; } diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index f96964a..cc77bc6 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -8,13 +8,20 @@ #include #endif +#include "app/drag_drop_types.h" #include "app/l10n_util.h" +#include "app/os_exchange_data.h" #include "app/resource_bundle.h" +#include "base/command_line.h" #include "base/i18n/rtl.h" +#include "base/keyboard_codes.h" +#include "base/time.h" +#include "build/build_config.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/app_modal_dialog_queue.h" #include "chrome/browser/automation/ui_controls.h" #include "chrome/browser/bookmarks/bookmark_utils.h" +#include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_theme_provider.h" @@ -23,30 +30,40 @@ #include "chrome/browser/ntp_background_util.h" #include "chrome/browser/page_info_window.h" #include "chrome/browser/pref_service.h" -#include "chrome/browser/sessions/tab_restore_service.h" -#include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/browser/profile.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/accessible_view_helper.h" #include "chrome/browser/views/bookmark_bar_view.h" +#include "chrome/browser/views/browser_bubble.h" #include "chrome/browser/views/browser_dialogs.h" +#include "chrome/browser/views/chrome_views_delegate.h" #include "chrome/browser/views/download_shelf_view.h" #include "chrome/browser/views/extensions/extension_shelf.h" -#include "chrome/browser/views/frame/browser_extender.h" #include "chrome/browser/views/frame/browser_view_layout.h" +#include "chrome/browser/views/frame/browser_extender.h" +#include "chrome/browser/views/frame/browser_frame.h" #include "chrome/browser/views/fullscreen_exit_bubble.h" +#include "chrome/browser/views/infobars/infobar_container.h" #include "chrome/browser/views/status_bubble_views.h" #include "chrome/browser/views/tab_contents/tab_contents_container.h" #include "chrome/browser/views/tabs/browser_tab_strip_controller.h" #include "chrome/browser/views/tabs/side_tab_strip.h" +#include "chrome/browser/views/tabs/tab_strip.h" #include "chrome/browser/views/theme_install_bubble_view.h" +#include "chrome/browser/views/toolbar_star_toggle.h" #include "chrome/browser/views/toolbar_view.h" +#include "chrome/browser/sessions/tab_restore_service.h" +#include "chrome/browser/tab_contents/navigation_entry.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/browser/window_sizer.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/native_web_keyboard_event.h" #include "chrome/common/native_window_notification_source.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" #include "gfx/canvas.h" +#include "gfx/scrollbar_size.h" #include "grit/app_resources.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" @@ -54,11 +71,14 @@ #include "grit/theme_resources.h" #include "grit/webkit_resources.h" #include "views/controls/single_split_view.h" +#include "views/fill_layout.h" #include "views/focus/external_focus_tracker.h" #include "views/focus/view_storage.h" #include "views/grid_layout.h" +#include "views/view.h" #include "views/widget/root_view.h" #include "views/window/dialog_delegate.h" +#include "views/window/non_client_view.h" #include "views/window/window.h" #if defined(OS_WIN) @@ -769,7 +789,7 @@ void BrowserView::UpdateLoadingAnimations(bool should_animate) { } void BrowserView::SetStarredState(bool is_starred) { - toolbar_->location_bar()->SetStarToggled(is_starred); + toolbar_->star_button()->SetToggled(is_starred); } gfx::Rect BrowserView::GetRestoredBounds() const { @@ -949,7 +969,7 @@ void BrowserView::ShowBookmarkManager() { } void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) { - toolbar_->location_bar()->ShowStarBubble(url, !already_bookmarked); + toolbar_->star_button()->ShowStarBubble(url, !already_bookmarked); } void BrowserView::SetDownloadShelfVisible(bool visible) { diff --git a/chrome/browser/views/frame/glass_browser_frame_view.cc b/chrome/browser/views/frame/glass_browser_frame_view.cc index 9a665f7..608fea9 100644 --- a/chrome/browser/views/frame/glass_browser_frame_view.cc +++ b/chrome/browser/views/frame/glass_browser_frame_view.cc @@ -40,8 +40,6 @@ const int kOTRBottomSpacing = 2; // There are 2 px on each side of the OTR avatar (between the frame border and // it on the left, and between it and the tabstrip on the right). const int kOTRSideSpacing = 2; -// The content left/right images have a shadow built into them. -const int kContentEdgeShadowThickness = 2; // The top 1 px of the tabstrip is shadow; in maximized mode we push this off // the top of the screen so the tabs appear flush against the screen edge. const int kTabstripTopShadowThickness = 1; @@ -263,46 +261,19 @@ void GlassBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) { toolbar_bounds.x() - 1, toolbar_bounds.y() + 2, toolbar_bounds.width() + 2, theme_toolbar->height()); - // Draw rounded corners for the tab. - SkBitmap* toolbar_left_mask = - tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK); - SkBitmap* toolbar_right_mask = - tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER_MASK); - - // We mask out the corners by using the DestinationIn transfer mode, - // which keeps the RGB pixels from the destination and the alpha from - // the source. - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kDstIn_Mode); - - // Mask out the top left corner. - int left_x = toolbar_bounds.x() - kContentEdgeShadowThickness - - kClientEdgeThickness; - canvas->DrawBitmapInt(*toolbar_left_mask, - left_x, toolbar_bounds.y(), paint); - - // Mask out the top right corner. - int right_x = toolbar_bounds.right() - toolbar_right_mask->width() + - kContentEdgeShadowThickness + kClientEdgeThickness; - canvas->DrawBitmapInt(*toolbar_right_mask, - right_x, toolbar_bounds.y(), - paint); - - // Draw left edge. - SkBitmap* toolbar_left = tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER); - canvas->DrawBitmapInt(*toolbar_left, left_x, toolbar_bounds.y()); - - // Draw center edge. + SkBitmap* toolbar_left = + tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER); + canvas->DrawBitmapInt(*toolbar_left, + toolbar_bounds.x() - toolbar_left->width(), + toolbar_bounds.y()); + SkBitmap* toolbar_center = tp->GetBitmapNamed(IDR_CONTENT_TOP_CENTER); - canvas->TileImageInt(*toolbar_center, left_x + toolbar_left->width(), - toolbar_bounds.y(), - right_x - (left_x + toolbar_left->width()), - toolbar_center->height()); + canvas->TileImageInt(*toolbar_center, toolbar_bounds.x(), toolbar_bounds.y(), + toolbar_bounds.width(), toolbar_center->height()); - // Right edge. canvas->DrawBitmapInt(*tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER), - right_x, toolbar_bounds.y()); + toolbar_bounds.right(), toolbar_bounds.y()); // Draw the content/toolbar separator. canvas->DrawLineInt(ResourceBundle::toolbar_separator_color, diff --git a/chrome/browser/views/frame/opaque_browser_frame_view.cc b/chrome/browser/views/frame/opaque_browser_frame_view.cc index c91cb51..e9276f8 100644 --- a/chrome/browser/views/frame/opaque_browser_frame_view.cc +++ b/chrome/browser/views/frame/opaque_browser_frame_view.cc @@ -26,7 +26,6 @@ #include "views/widget/root_view.h" #include "views/window/window.h" #include "views/window/window_resources.h" -#include "views/window/window_shape.h" #if defined(OS_WIN) #include "app/win_util.h" @@ -59,8 +58,6 @@ const int kResizeAreaCornerSize = 16; // The titlebar never shrinks too short to show the caption button plus some // padding below it. const int kCaptionButtonHeightWithPadding = 19; -// The content left/right images have a shadow built into them. -const int kContentEdgeShadowThickness = 2; // The titlebar has a 2 px 3D edge along the top and bottom. const int kTitlebarTopAndBottomEdgeThickness = 2; // The icon is inset 2 px from the left frame border. @@ -92,9 +89,6 @@ const int kNewTabCaptionRestoredSpacing = 5; // similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid // looking too cluttered. const int kNewTabCaptionMaximizedSpacing = 16; -// How far to indent the tabstrip from the left side of the screen when there -// is no OTR icon. -const int kTabStripIndent = 1; } /////////////////////////////////////////////////////////////////////////////// @@ -194,7 +188,7 @@ gfx::Rect OpaqueBrowserFrameView::GetBoundsForTabStrip( BaseTabStrip* tabstrip) const { int tabstrip_x = browser_view_->ShouldShowOffTheRecordAvatar() ? (otr_avatar_icon_->bounds().right() + kOTRSideSpacing) : - NonClientBorderThickness() + kTabStripIndent; + NonClientBorderThickness(); int tabstrip_width = minimize_button_->x() - tabstrip_x - (frame_->GetWindow()->IsMaximized() ? kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing); @@ -304,7 +298,23 @@ void OpaqueBrowserFrameView::GetWindowMask(const gfx::Size& size, if (frame_->GetWindow()->IsMaximized() || frame_->GetWindow()->IsFullscreen()) return; - views::GetDefaultWindowMask(size, window_mask); + // Redefine the window visible region for the new size. + window_mask->moveTo(0, 3); + window_mask->lineTo(1, 2); + window_mask->lineTo(1, 1); + window_mask->lineTo(2, 1); + window_mask->lineTo(3, 0); + + window_mask->lineTo(SkIntToScalar(size.width() - 3), 0); + window_mask->lineTo(SkIntToScalar(size.width() - 2), 1); + window_mask->lineTo(SkIntToScalar(size.width() - 1), 1); + window_mask->lineTo(SkIntToScalar(size.width() - 1), 2); + window_mask->lineTo(SkIntToScalar(size.width()), 3); + + window_mask->lineTo(SkIntToScalar(size.width()), + SkIntToScalar(size.height())); + window_mask->lineTo(0, SkIntToScalar(size.height())); + window_mask->close(); } void OpaqueBrowserFrameView::EnableClose(bool enable) { @@ -707,17 +717,6 @@ void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) { int bottom_edge_height = std::min(toolbar_left->height(), toolbar_bounds.height()) - split_point; - // Split our canvas out so we can mask out the corners of the toolbar - // without masking out the frame. - SkRect bounds; - bounds.set(SkIntToScalar(toolbar_bounds.x() - kClientEdgeThickness), - SkIntToScalar(toolbar_bounds.y()), - SkIntToScalar(toolbar_bounds.x() + toolbar_bounds.width() + - kClientEdgeThickness * 2), - SkIntToScalar(toolbar_bounds.y() + toolbar_bounds.height())); - canvas->saveLayerAlpha(&bounds, 255); - canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); - SkColor theme_toolbar_color = tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR); canvas->FillRectInt(theme_toolbar_color, toolbar_bounds.x(), bottom_y, @@ -733,65 +732,26 @@ void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) { toolbar_bounds.width() + (2 * kClientEdgeThickness), theme_toolbar->height()); - // Draw rounded corners for the tab. - SkBitmap* toolbar_left_mask = - tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK); - SkBitmap* toolbar_right_mask = - tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER_MASK); - - // We mask out the corners by using the DestinationIn transfer mode, - // which keeps the RGB pixels from the destination and the alpha from - // the source. - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kDstIn_Mode); - - // Make the left edge. - int left_x = toolbar_bounds.x() - kClientEdgeThickness - - kContentEdgeShadowThickness; - canvas->DrawBitmapInt(*toolbar_left_mask, 0, 0, - toolbar_left_mask->width(), split_point, - left_x, toolbar_bounds.y(), - toolbar_left_mask->width(), split_point, false, paint); - canvas->DrawBitmapInt(*toolbar_left_mask, 0, - toolbar_left_mask->height() - bottom_edge_height, - toolbar_left_mask->width(), bottom_edge_height, - left_x, bottom_y, - toolbar_left_mask->width(), bottom_edge_height, false, paint); - - // Mask the right edge. - int right_x = toolbar_bounds.right() - - toolbar_right_mask->width() + kClientEdgeThickness + - kContentEdgeShadowThickness; - canvas->DrawBitmapInt(*toolbar_right_mask, 0, 0, - toolbar_right_mask->width(), split_point, right_x, toolbar_bounds.y(), - toolbar_right_mask->width(), split_point, false, paint); - canvas->DrawBitmapInt(*toolbar_right_mask, 0, - toolbar_right_mask->height() - bottom_edge_height, - toolbar_right_mask->width(), bottom_edge_height, right_x, bottom_y, - toolbar_right_mask->width(), bottom_edge_height, false, paint); - canvas->restore(); - canvas->DrawBitmapInt(*toolbar_left, 0, 0, toolbar_left->width(), split_point, - left_x, toolbar_bounds.y(), + toolbar_bounds.x() - toolbar_left->width(), toolbar_bounds.y(), toolbar_left->width(), split_point, false); canvas->DrawBitmapInt(*toolbar_left, 0, toolbar_left->height() - bottom_edge_height, toolbar_left->width(), - bottom_edge_height, left_x, bottom_y, + bottom_edge_height, toolbar_bounds.x() - toolbar_left->width(), bottom_y, toolbar_left->width(), bottom_edge_height, false); SkBitmap* toolbar_center = tp->GetBitmapNamed(IDR_CONTENT_TOP_CENTER); - canvas->TileImageInt(*toolbar_center, 0, 0, left_x + toolbar_left->width(), - toolbar_bounds.y(), right_x - (left_x + toolbar_left->width()), - split_point); + canvas->TileImageInt(*toolbar_center, 0, 0, toolbar_bounds.x(), + toolbar_bounds.y(), toolbar_bounds.width(), split_point); SkBitmap* toolbar_right = tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER); canvas->DrawBitmapInt(*toolbar_right, 0, 0, toolbar_right->width(), - split_point, right_x, toolbar_bounds.y(), + split_point, toolbar_bounds.right(), toolbar_bounds.y(), toolbar_right->width(), split_point, false); canvas->DrawBitmapInt(*toolbar_right, 0, toolbar_right->height() - bottom_edge_height, toolbar_right->width(), - bottom_edge_height, right_x, bottom_y, + bottom_edge_height, toolbar_bounds.right(), bottom_y, toolbar_right->width(), bottom_edge_height, false); // Draw the content/toolbar separator. diff --git a/chrome/browser/views/info_bubble.cc b/chrome/browser/views/info_bubble.cc index 8150db9..e5c4858 100644 --- a/chrome/browser/views/info_bubble.cc +++ b/chrome/browser/views/info_bubble.cc @@ -29,17 +29,55 @@ const SkColor InfoBubble::kBackgroundColor = const SkColor InfoBubble::kBackgroundColor = SK_ColorWHITE; #endif +// BorderContents ------------------------------------------------------------- + +// This is used to paint the border of the InfoBubble. Windows uses this via +// BorderWidget (see below), while others can use it directly in the bubble. +class BorderContents : public views::View { + public: + BorderContents() { } + + // Given the size of the contents and the rect to point at, initializes the + // bubble and returns the bounds of both the border + // and the contents inside the bubble. + // |prefer_arrow_on_right| specifies the preferred location for the arrow + // anchor. If the bubble does not fit on the monitor, the arrow location may + // changed so it can. + // + // TODO(pkasting): Maybe this should use mirroring transformations instead, + // which would hopefully simplify this code. + void InitAndGetBounds( + const gfx::Rect& position_relative_to, // In screen coordinates + const gfx::Size& contents_size, + bool prefer_arrow_on_right, + gfx::Rect* contents_bounds, // Returned in window coordinates + gfx::Rect* window_bounds); // Returned in screen coordinates + + private: + virtual ~BorderContents() { } + + // Overridden from View: + virtual void Paint(gfx::Canvas* canvas); + + DISALLOW_COPY_AND_ASSIGN(BorderContents); +}; + void BorderContents::InitAndGetBounds( const gfx::Rect& position_relative_to, const gfx::Size& contents_size, bool prefer_arrow_on_right, gfx::Rect* contents_bounds, gfx::Rect* window_bounds) { + // Margins between the contents and the inside of the border, in pixels. + const int kLeftMargin = 6; + const int kTopMargin = 6; + const int kRightMargin = 6; + const int kBottomMargin = 9; + // Set the border. - if (!bubble_border_) - bubble_border_ = new BubbleBorder; - set_border(bubble_border_); - bubble_border_->set_background_color(InfoBubble::kBackgroundColor); + BubbleBorder* bubble_border = new BubbleBorder; + set_border(bubble_border); + bubble_border->set_background_color(InfoBubble::kBackgroundColor); // Give the contents a margin. gfx::Size local_contents_size(contents_size); @@ -50,9 +88,9 @@ void BorderContents::InitAndGetBounds( // bounds. BubbleBorder::ArrowLocation arrow_location(prefer_arrow_on_right ? BubbleBorder::TOP_RIGHT : BubbleBorder::TOP_LEFT); - bubble_border_->set_arrow_location(arrow_location); + bubble_border->set_arrow_location(arrow_location); *window_bounds = - bubble_border_->GetBounds(position_relative_to, local_contents_size); + bubble_border->GetBounds(position_relative_to, local_contents_size); // See if those bounds will fit on the monitor. scoped_ptr monitor_provider( @@ -71,10 +109,10 @@ void BorderContents::InitAndGetBounds( arrow_location = arrow_on_left ? BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT; } - bubble_border_->set_arrow_location(arrow_location); + bubble_border->set_arrow_location(arrow_location); // Now get the recalculated bounds. - *window_bounds = bubble_border_->GetBounds(position_relative_to, + *window_bounds = bubble_border->GetBounds(position_relative_to, local_contents_size); } @@ -82,7 +120,7 @@ void BorderContents::InitAndGetBounds( // subtracting the border dimensions and margin amounts. *contents_bounds = gfx::Rect(gfx::Point(), window_bounds->size()); gfx::Insets insets; - bubble_border_->GetInsets(&insets); + bubble_border->GetInsets(&insets); contents_bounds->Inset(insets.left() + kLeftMargin, insets.top() + kTopMargin, insets.right() + kRightMargin, insets.bottom() + kBottomMargin); } @@ -90,8 +128,6 @@ void BorderContents::InitAndGetBounds( void BorderContents::Paint(gfx::Canvas* canvas) { // The border of this view creates an anti-aliased round-rect region for the // contents, which we need to fill with the background color. - // NOTE: This doesn't handle an arrow location of "NONE", which has square top - // corners. SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kFill_Style); @@ -114,7 +150,7 @@ void BorderContents::Paint(gfx::Canvas* canvas) { #if defined(OS_WIN) // BorderWidget --------------------------------------------------------------- -BorderWidget::BorderWidget() : border_contents_(NULL) { +BorderWidget::BorderWidget() { set_delete_on_destroy(false); // Our owner will free us manually. set_window_style(WS_POPUP); set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED); @@ -127,16 +163,15 @@ gfx::Rect BorderWidget::InitAndGetBounds( bool prefer_arrow_on_right) { // Set up the border view and ask it to calculate our bounds (and our // contents'). - if (!border_contents_) - border_contents_ = new BorderContents; + BorderContents* border_contents = new BorderContents; gfx::Rect contents_bounds, window_bounds; - border_contents_->InitAndGetBounds(position_relative_to, contents_size, - prefer_arrow_on_right, &contents_bounds, - &window_bounds); + border_contents->InitAndGetBounds(position_relative_to, contents_size, + prefer_arrow_on_right, &contents_bounds, + &window_bounds); // Initialize ourselves. WidgetWin::Init(GetAncestor(owner, GA_ROOT), window_bounds); - SetContentsView(border_contents_); + SetContentsView(border_contents); SetWindowPos(owner, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW); @@ -233,8 +268,7 @@ void InfoBubble::Init(views::Window* parent, (contents->UILayoutIsRightToLeft() == delegate->PreferOriginSideAnchor()); #if defined(OS_WIN) - if (!border_.get()) - border_.reset(new BorderWidget); + border_.reset(new BorderWidget); // Initialize and position the border window. window_bounds = border_->InitAndGetBounds(GetNativeView(), position_relative_to, contents->GetPreferredSize(), diff --git a/chrome/browser/views/info_bubble.h b/chrome/browser/views/info_bubble.h index ea80b0f..90911b5 100644 --- a/chrome/browser/views/info_bubble.h +++ b/chrome/browser/views/info_bubble.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,7 +7,6 @@ #include "third_party/skia/include/core/SkColor.h" #include "views/accelerator.h" -#include "views/view.h" #if defined(OS_WIN) #include "views/widget/widget_win.h" #elif defined(OS_LINUX) @@ -24,7 +23,6 @@ // have any additional margins. class BorderWidget; -class BubbleBorder; class InfoBubble; namespace views { @@ -35,46 +33,6 @@ namespace gfx { class Path; } -// This is used to paint the border of the InfoBubble. Windows uses this via -// BorderWidget (see below), while others can use it directly in the bubble. -class BorderContents : public views::View { - public: - BorderContents() : bubble_border_(NULL) { } - - // Given the size of the contents and the rect to point at, initializes the - // bubble and returns the bounds of both the border - // and the contents inside the bubble. - // |prefer_arrow_on_right| specifies the preferred location for the arrow - // anchor. If the bubble does not fit on the monitor, the arrow location may - // changed so it can. - // - // TODO(pkasting): Maybe this should use mirroring transformations instead, - // which would hopefully simplify this code. - virtual void InitAndGetBounds( - const gfx::Rect& position_relative_to, // In screen coordinates - const gfx::Size& contents_size, - bool prefer_arrow_on_right, - gfx::Rect* contents_bounds, // Returned in window coordinates - gfx::Rect* window_bounds); // Returned in screen coordinates - - protected: - virtual ~BorderContents() { } - - // Margins between the contents and the inside of the border, in pixels. - static const int kLeftMargin = 6; - static const int kTopMargin = 6; - static const int kRightMargin = 6; - static const int kBottomMargin = 9; - - BubbleBorder* bubble_border_; - - private: - // Overridden from View: - virtual void Paint(gfx::Canvas* canvas); - - DISALLOW_COPY_AND_ASSIGN(BorderContents); -}; - #if defined(OS_WIN) // This is a window that surrounds the info bubble and paints the margin and // border. It is a separate window so that it can be a layered window, so that @@ -89,15 +47,12 @@ class BorderWidget : public views::WidgetWin { // Given the owning (parent) window, the size of the contained contents // (without margins), and the rect (in screen coordinates) to point to, // initializes the window and returns the bounds (in screen coordinates) the - // contents should use. |is_rtl| is supplied to + // contents should use. |is_rtl| is supplied to // BorderContents::InitAndGetBounds(), see its declaration for details. - virtual gfx::Rect InitAndGetBounds(HWND owner, - const gfx::Rect& position_relative_to, - const gfx::Size& contents_size, - bool is_rtl); - - protected: - BorderContents* border_contents_; + gfx::Rect InitAndGetBounds(HWND owner, + const gfx::Rect& position_relative_to, + const gfx::Size& contents_size, + bool is_rtl); private: // Overridden from WidgetWin: @@ -127,7 +82,7 @@ class InfoBubbleDelegate { virtual bool PreferOriginSideAnchor() { return true; } }; -// TODO(sky): this code is ifdef-tastic. It might be cleaner to refactor the +// TODO: this code is ifdef-tastic. It might be cleaner to refactor the // WidgetFoo subclass into a separate class that calls into InfoBubble. // That way InfoBubble has no (or very few) ifdefs. class InfoBubble @@ -165,10 +120,10 @@ class InfoBubble virtual ~InfoBubble() {} // Creates the InfoBubble. - virtual void Init(views::Window* parent, - const gfx::Rect& position_relative_to, - views::View* contents, - InfoBubbleDelegate* delegate); + void Init(views::Window* parent, + const gfx::Rect& position_relative_to, + views::View* contents, + InfoBubbleDelegate* delegate); #if defined(OS_WIN) // Overridden from WidgetWin: @@ -178,11 +133,6 @@ class InfoBubble virtual void IsActiveChanged(); #endif -#if defined(OS_WIN) - // The window used to render the padding, border and arrow. - scoped_ptr border_; -#endif - private: // Closes the window notifying the delegate. |closed_by_escape| is true if // the close is the result of pressing escape. @@ -197,6 +147,11 @@ class InfoBubble // The window that this InfoBubble is parented to. views::Window* parent_; +#if defined(OS_WIN) + // The window used to render the padding, border and arrow. + scoped_ptr border_; +#endif + // Have we been closed? bool closed_; diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc index a4e6da7..b9e36d5 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -8,7 +8,6 @@ #include #endif -#include "app/drag_drop_types.h" #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "app/theme_provider.h" @@ -17,6 +16,8 @@ #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/alternate_nav_url_fetcher.h" #include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/bubble_positioner.h" #include "chrome/browser/command_updater.h" #include "chrome/browser/content_setting_bubble_model.h" #include "chrome/browser/content_setting_image_model.h" @@ -25,15 +26,17 @@ #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/view_ids.h" -#include "chrome/browser/views/browser_dialogs.h" -#include "chrome/browser/views/content_blocked_bubble_contents.h" +#include "chrome/browser/views/extensions/extension_popup.h" #include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/content_blocked_bubble_contents.h" +#include "chrome/common/content_settings.h" #include "chrome/common/platform_util.h" +#include "chrome/common/pref_names.h" #include "gfx/canvas.h" #include "gfx/color_utils.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" -#include "views/drag_utils.h" +#include "net/base/net_util.h" #if defined(OS_WIN) #include "chrome/browser/views/first_run_bubble.h" @@ -44,31 +47,20 @@ using views::View; // static const int LocationBarView::kVertMargin = 2; -// Padding between items in the location bar. -static const int kViewPadding = 3; - -// Padding before the start of a bubble. -static const int kBubblePadding = kViewPadding - 1; - -// Padding between the location icon and the edit, if they're adjacent. -static const int kLocationIconEditPadding = kViewPadding - 1; +// Padding on the right and left of the entry field. +static const int kEntryPadding = 3; -static const int kEVBubbleBackgroundImages[] = { - IDR_OMNIBOX_EV_BUBBLE_BACKGROUND_L, - IDR_OMNIBOX_EV_BUBBLE_BACKGROUND_C, - IDR_OMNIBOX_EV_BUBBLE_BACKGROUND_R, -}; - -static const int kSelectedKeywordBackgroundImages[] = { - IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_L, - IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_C, - IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_R, -}; +// Padding between the entry and the leading/trailing views. +static const int kInnerPadding = 3; static const SkBitmap* kBackground = NULL; static const SkBitmap* kPopupBackground = NULL; +// The delay the mouse has to be hovering over the lock/warning icon before the +// info bubble is shown. +static const int kInfoBubbleHoverDelayMs = 500; + // The tab key image. static const SkBitmap* kTabButtonBitmap = NULL; @@ -140,23 +132,21 @@ LocationBarView::LocationBarView(Profile* profile, CommandUpdater* command_updater, ToolbarModel* model, Delegate* delegate, - bool popup_window_mode) + bool popup_window_mode, + const BubblePositioner* bubble_positioner) : profile_(profile), command_updater_(command_updater), model_(model), delegate_(delegate), disposition_(CURRENT_TAB), - ALLOW_THIS_IN_INITIALIZER_LIST(location_icon_view_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(ev_bubble_view_( - kEVBubbleBackgroundImages, IDR_OMNIBOX_HTTPS_VALID, - GetColor(ToolbarModel::EV_SECURE, SECURITY_TEXT), this)), location_entry_view_(NULL), - selected_keyword_view_(kSelectedKeywordBackgroundImages, - IDR_OMNIBOX_SEARCH, SK_ColorBLACK, profile), + selected_keyword_view_(profile), keyword_hint_view_(profile), - star_view_(command_updater), + type_to_search_view_(l10n_util::GetString(IDS_OMNIBOX_EMPTY_TEXT)), + security_image_view_(this, profile, model, bubble_positioner), popup_window_mode_(popup_window_mode), - ALLOW_THIS_IN_INITIALIZER_LIST(first_run_bubble_(this)) { + first_run_bubble_(this), + bubble_positioner_(bubble_positioner) { DCHECK(profile_); SetID(VIEW_ID_LOCATION_BAR); SetFocusable(true); @@ -180,45 +170,52 @@ void LocationBarView::Init() { font_ = font_.DeriveFont(3); } - AddChildView(&location_icon_view_); - location_icon_view_.SetVisible(true); - location_icon_view_.SetDragController(this); - location_icon_view_.set_parent_owned(false); - - AddChildView(&ev_bubble_view_); - ev_bubble_view_.SetVisible(false); - ev_bubble_view_.SetDragController(this); - ev_bubble_view_.set_parent_owned(false); - // URL edit field. // View container for URL edit field. #if defined(OS_WIN) + views::Widget* widget = GetWidget(); location_entry_.reset(new AutocompleteEditViewWin(font_, this, model_, this, - GetWidget()->GetNativeView(), profile_, command_updater_, - popup_window_mode_, this)); + widget->GetNativeView(), + profile_, command_updater_, + popup_window_mode_, + bubble_positioner_)); #else location_entry_.reset(new AutocompleteEditViewGtk(this, model_, profile_, - command_updater_, popup_window_mode_, this)); + command_updater_, + popup_window_mode_, + bubble_positioner_)); location_entry_->Init(); // Make all the children of the widget visible. NOTE: this won't display // anything, it just toggles the visible flag. - gtk_widget_show_all(location_entry_->GetNativeView()); + gtk_widget_show_all(location_entry_->widget()); // Hide the widget. NativeViewHostGtk will make it visible again as // necessary. - gtk_widget_hide(location_entry_->GetNativeView()); + gtk_widget_hide(location_entry_->widget()); #endif location_entry_view_ = new views::NativeViewHost; location_entry_view_->SetID(VIEW_ID_AUTOCOMPLETE); AddChildView(location_entry_view_); location_entry_view_->set_focus_view(this); - location_entry_view_->Attach(location_entry_->GetNativeView()); + location_entry_view_->Attach( +#if defined(OS_WIN) + location_entry_->m_hWnd +#else + location_entry_->widget() +#endif + ); // NOLINT AddChildView(&selected_keyword_view_); selected_keyword_view_.SetFont(font_); selected_keyword_view_.SetVisible(false); selected_keyword_view_.set_parent_owned(false); - SkColor dimmed_text = GetColor(ToolbarModel::NONE, DEEMPHASIZED_TEXT); + SkColor dimmed_text = GetColor(false, DEEMPHASIZED_TEXT); + + AddChildView(&type_to_search_view_); + type_to_search_view_.SetVisible(false); + type_to_search_view_.SetFont(font_); + type_to_search_view_.SetColor(dimmed_text); + type_to_search_view_.set_parent_owned(false); AddChildView(&keyword_hint_view_); keyword_hint_view_.SetVisible(false); @@ -226,19 +223,22 @@ void LocationBarView::Init() { keyword_hint_view_.SetColor(dimmed_text); keyword_hint_view_.set_parent_owned(false); + AddChildView(&security_image_view_); + security_image_view_.SetVisible(false); + security_image_view_.set_parent_owned(false); + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { - ContentSettingImageView* content_blocked_view = new ContentSettingImageView( - static_cast(i), this, profile_); + ContentSettingImageView* content_blocked_view = + new ContentSettingImageView(static_cast(i), this, + profile_, bubble_positioner_); content_setting_views_.push_back(content_blocked_view); AddChildView(content_blocked_view); content_blocked_view->SetVisible(false); } - if (!popup_window_mode_) { - AddChildView(&star_view_); - star_view_.SetVisible(true); - star_view_.set_parent_owned(false); - } + AddChildView(&info_label_); + info_label_.SetVisible(false); + info_label_.set_parent_owned(false); // Notify us when any ancestor is resized. In this case we want to tell the // AutocompleteEditView to close its popup. @@ -256,59 +256,63 @@ bool LocationBarView::IsInitialized() const { } // static -SkColor LocationBarView::GetColor(ToolbarModel::SecurityLevel security_level, - ColorKind kind) { - switch (kind) { +SkColor LocationBarView::GetColor(bool is_secure, ColorKind kind) { + enum SecurityState { + NOT_SECURE = 0, + SECURE, + NUM_STATES + }; + + static bool initialized = false; + static SkColor colors[NUM_STATES][NUM_KINDS]; + if (!initialized) { #if defined(OS_WIN) - case BACKGROUND: return color_utils::GetSysSkColor(COLOR_WINDOW); - case TEXT: return color_utils::GetSysSkColor(COLOR_WINDOWTEXT); - case SELECTED_TEXT: return color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT); + colors[NOT_SECURE][BACKGROUND] = color_utils::GetSysSkColor(COLOR_WINDOW); + colors[NOT_SECURE][TEXT] = color_utils::GetSysSkColor(COLOR_WINDOWTEXT); + colors[NOT_SECURE][SELECTED_TEXT] = + color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT); #else // TODO(beng): source from theme provider. - case BACKGROUND: return SK_ColorWHITE; - case TEXT: return SK_ColorBLACK; - case SELECTED_TEXT: return SK_ColorWHITE; + colors[NOT_SECURE][BACKGROUND] = SK_ColorWHITE; + colors[NOT_SECURE][TEXT] = SK_ColorBLACK; + colors[NOT_SECURE][SELECTED_TEXT] = SK_ColorWHITE; #endif - - case DEEMPHASIZED_TEXT: - return color_utils::AlphaBlend(GetColor(security_level, TEXT), - GetColor(security_level, BACKGROUND), 128); - - case SECURITY_TEXT: { - SkColor color; - switch (security_level) { - case ToolbarModel::EV_SECURE: - case ToolbarModel::SECURE: - color = SkColorSetRGB(7, 149, 0); - break; - - case ToolbarModel::SECURITY_WARNING: - return GetColor(security_level, DEEMPHASIZED_TEXT); - break; - - case ToolbarModel::SECURITY_ERROR: - color = SkColorSetRGB(162, 0, 0); - break; - - default: - NOTREACHED(); - return GetColor(security_level, TEXT); - } - return color_utils::GetReadableColor(color, GetColor(security_level, - BACKGROUND)); - } - - default: - NOTREACHED(); - return GetColor(security_level, TEXT); + colors[SECURE][BACKGROUND] = SkColorSetRGB(255, 245, 195); + colors[SECURE][TEXT] = SK_ColorBLACK; + colors[SECURE][SELECTED_TEXT] = 0; // Unused + colors[NOT_SECURE][DEEMPHASIZED_TEXT] = + color_utils::AlphaBlend(colors[NOT_SECURE][TEXT], + colors[NOT_SECURE][BACKGROUND], 128); + colors[SECURE][DEEMPHASIZED_TEXT] = + color_utils::AlphaBlend(colors[SECURE][TEXT], + colors[SECURE][BACKGROUND], 128); + colors[NOT_SECURE][SECURITY_TEXT] = color_utils::GetReadableColor( + SkColorSetRGB(200, 0, 0), colors[NOT_SECURE][BACKGROUND]); + colors[SECURE][SECURITY_TEXT] = SkColorSetRGB(0, 150, 20); + colors[NOT_SECURE][SECURITY_INFO_BUBBLE_TEXT] = + colors[NOT_SECURE][SECURITY_TEXT]; + colors[SECURE][SECURITY_INFO_BUBBLE_TEXT] = color_utils::GetReadableColor( + SkColorSetRGB(0, 153, 51), colors[NOT_SECURE][BACKGROUND]); + colors[NOT_SECURE][SCHEME_STRIKEOUT] = color_utils::GetReadableColor( + SkColorSetRGB(210, 0, 0), colors[NOT_SECURE][BACKGROUND]); + colors[SECURE][SCHEME_STRIKEOUT] = 0; // Unused + initialized = true; } + + return colors[is_secure ? SECURE : NOT_SECURE][kind]; } void LocationBarView::Update(const TabContents* tab_for_state_restoring) { + SetSecurityIcon(model_->GetIcon()); RefreshContentSettingViews(); RefreshPageActionViews(); + std::wstring info_text, info_tooltip; + ToolbarModel::InfoTextType info_text_type = + model_->GetInfoText(&info_text, &info_tooltip); + SetInfoText(info_text, info_text_type, info_tooltip); location_entry_->Update(tab_for_state_restoring); - OnChanged(); + Layout(); + SchedulePaint(); } void LocationBarView::UpdateContentSettingsIcons() { @@ -358,6 +362,7 @@ void LocationBarView::SetProfile(Profile* profile) { for (ContentSettingViews::const_iterator i(content_setting_views_.begin()); i != content_setting_views_.end(); ++i) (*i)->set_profile(profile); + security_image_view_.set_profile(profile); } } @@ -365,11 +370,8 @@ TabContents* LocationBarView::GetTabContents() const { return delegate_->GetTabContents(); } -void LocationBarView::SetPreviewEnabledPageAction(ExtensionAction* page_action, +void LocationBarView::SetPreviewEnabledPageAction(ExtensionAction *page_action, bool preview_enabled) { - if (popup_window_mode_) - return; - DCHECK(page_action); TabContents* contents = delegate_->GetTabContents(); @@ -398,156 +400,13 @@ views::View* LocationBarView::GetPageActionView( return NULL; } -void LocationBarView::SetStarToggled(bool on) { - star_view_.SetToggled(on); -} - -void LocationBarView::ShowStarBubble(const GURL& url, bool newly_bookmarked) { - gfx::Rect screen_bounds(star_view_.GetImageBounds()); - // Compensate for some built-in padding in the Star image. - screen_bounds.Inset(1, 1, 1, 2); - gfx::Point origin(screen_bounds.origin()); - views::View::ConvertPointToScreen(&star_view_, &origin); - screen_bounds.set_origin(origin); - browser::ShowBookmarkBubbleView(GetWindow(), screen_bounds, &star_view_, - profile_, url, newly_bookmarked); -} - gfx::Size LocationBarView::GetPreferredSize() { return gfx::Size(0, (popup_window_mode_ ? kPopupBackground : kBackground)->height()); } void LocationBarView::Layout() { - if (!location_entry_.get()) - return; - - int entry_width = width() - kViewPadding; - - // |location_icon_view_| is visible except when |ev_bubble_view_| or - // |selected_keyword_view_| are visible. - int location_icon_width = 0; - int ev_bubble_width = 0; - location_icon_view_.SetVisible(false); - ev_bubble_view_.SetVisible(false); - const std::wstring keyword(location_entry_->model()->keyword()); - const bool is_keyword_hint(location_entry_->model()->is_keyword_hint()); - const bool show_selected_keyword = !keyword.empty() && !is_keyword_hint; - if (show_selected_keyword) { - entry_width -= kViewPadding; // Assume the keyword might be hidden. - } else if (model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) { - ev_bubble_view_.SetVisible(true); - ev_bubble_view_.SetLabel(model_->GetEVCertName()); - ev_bubble_width = ev_bubble_view_.GetPreferredSize().width(); - entry_width -= kBubblePadding + ev_bubble_width + kViewPadding; - } else { - location_icon_view_.SetVisible(true); - location_icon_width = location_icon_view_.GetPreferredSize().width(); - entry_width -= - kViewPadding + location_icon_width + kLocationIconEditPadding; - } - - entry_width -= star_view_.GetPreferredSize().width() + kViewPadding; - for (PageActionViews::const_iterator i(page_action_views_.begin()); - i != page_action_views_.end(); ++i) { - if ((*i)->IsVisible()) - entry_width -= (*i)->GetPreferredSize().width() + kViewPadding; - } - for (ContentSettingViews::const_iterator i(content_setting_views_.begin()); - i != content_setting_views_.end(); ++i) { - if ((*i)->IsVisible()) - entry_width -= (*i)->GetPreferredSize().width() + kViewPadding; - } - -#if defined(OS_WIN) - RECT formatting_rect; - location_entry_->GetRect(&formatting_rect); - RECT edit_bounds; - location_entry_->GetClientRect(&edit_bounds); - int max_edit_width = entry_width - formatting_rect.left - - (edit_bounds.right - formatting_rect.right); -#else - int max_edit_width = entry_width; -#endif - - if (max_edit_width < 0) - return; - const int available_width = AvailableWidth(max_edit_width); - - const bool show_keyword_hint = !keyword.empty() && is_keyword_hint; - selected_keyword_view_.SetVisible(show_selected_keyword); - keyword_hint_view_.SetVisible(show_keyword_hint); - if (show_selected_keyword) { - if (selected_keyword_view_.keyword() != keyword) - selected_keyword_view_.SetKeyword(keyword); - } else if (show_keyword_hint) { - if (keyword_hint_view_.keyword() != keyword) - keyword_hint_view_.SetKeyword(keyword); - } - - // TODO(sky): baseline layout. - int location_y = TopMargin(); - int location_height = std::max(height() - location_y - kVertMargin, 0); - - // Lay out items to the right of the edit field. - int offset = width() - kViewPadding; - int star_width = star_view_.GetPreferredSize().width(); - offset -= star_width; - star_view_.SetBounds(offset, location_y, star_width, location_height); - offset -= kViewPadding; - - for (PageActionViews::const_iterator i(page_action_views_.begin()); - i != page_action_views_.end(); ++i) { - if ((*i)->IsVisible()) { - int page_action_width = (*i)->GetPreferredSize().width(); - offset -= page_action_width; - (*i)->SetBounds(offset, location_y, page_action_width, location_height); - offset -= kViewPadding; - } - } - // We use a reverse_iterator here because we're laying out the views from - // right to left but in the vector they're ordered left to right. - for (ContentSettingViews::const_reverse_iterator - i(content_setting_views_.rbegin()); i != content_setting_views_.rend(); - ++i) { - if ((*i)->IsVisible()) { - int content_blocked_width = (*i)->GetPreferredSize().width(); - offset -= content_blocked_width; - (*i)->SetBounds(offset, location_y, content_blocked_width, - location_height); - offset -= kViewPadding; - } - } - - // Now lay out items to the left of the edit field. - if (location_icon_view_.IsVisible()) { - location_icon_view_.SetBounds(kViewPadding, location_y, location_icon_width, - location_height); - offset = location_icon_view_.bounds().right() + kLocationIconEditPadding; - } else if (ev_bubble_view_.IsVisible()) { - ev_bubble_view_.SetBounds(kBubblePadding, location_y, ev_bubble_width, - location_height); - offset = ev_bubble_view_.bounds().right() + kViewPadding; - } else { - offset = show_selected_keyword ? kBubblePadding : kViewPadding; - } - - // Now lay out the edit field and views that autocollapse to give it more - // room. - gfx::Rect location_bounds(offset, location_y, entry_width, location_height); - if (show_selected_keyword) { - LayoutView(true, &selected_keyword_view_, available_width, - &location_bounds); - if (!selected_keyword_view_.IsVisible()) { - location_bounds.set_x( - location_bounds.x() + kViewPadding - kBubblePadding); - } - } else if (show_keyword_hint) { - LayoutView(false, &keyword_hint_view_, available_width, - &location_bounds); - } - - location_entry_view_->SetBounds(location_bounds); + DoLayout(true); } void LocationBarView::Paint(gfx::Canvas* canvas) { @@ -560,9 +419,10 @@ void LocationBarView::Paint(gfx::Canvas* canvas) { canvas->TileImageInt(*background, 0, 0, 0, 0, width(), height()); int top_margin = TopMargin(); - canvas->FillRectInt(GetColor(ToolbarModel::NONE, BACKGROUND), 0, - top_margin, width(), - std::max(height() - top_margin - kVertMargin, 0)); + canvas->FillRectInt( + GetColor(model_->GetSchemeSecurityLevel() == ToolbarModel::SECURE, + BACKGROUND), + 0, top_margin, width(), std::max(height() - top_margin - kVertMargin, 0)); } void LocationBarView::VisibleBoundsInRootChanged() { @@ -649,11 +509,7 @@ void LocationBarView::OnAutocompleteAccept( } void LocationBarView::OnChanged() { - location_icon_view_.SetImage( - ResourceBundle::GetSharedInstance().GetBitmapNamed( - location_entry_->GetIcon())); - Layout(); - SchedulePaint(); + DoLayout(false); } void LocationBarView::OnInputInProgress(bool in_progress) { @@ -684,6 +540,117 @@ std::wstring LocationBarView::GetTitle() const { return UTF16ToWideHack(delegate_->GetTabContents()->GetTitle()); } +void LocationBarView::DoLayout(const bool force_layout) { + if (!location_entry_.get()) + return; + + int entry_width = width() - (kEntryPadding * 2); + + for (PageActionViews::const_iterator i(page_action_views_.begin()); + i != page_action_views_.end(); ++i) { + if ((*i)->IsVisible()) + entry_width -= (*i)->GetPreferredSize().width() + kInnerPadding; + } + for (ContentSettingViews::const_iterator i(content_setting_views_.begin()); + i != content_setting_views_.end(); ++i) { + if ((*i)->IsVisible()) + entry_width -= (*i)->GetPreferredSize().width() + kInnerPadding; + } + gfx::Size security_image_size; + if (security_image_view_.IsVisible()) { + security_image_size = security_image_view_.GetPreferredSize(); + entry_width -= security_image_size.width() + kInnerPadding; + } + gfx::Size info_label_size; + if (info_label_.IsVisible()) { + info_label_size = info_label_.GetPreferredSize(); + entry_width -= (info_label_size.width() + kInnerPadding); + } + +#if defined(OS_WIN) + RECT formatting_rect; + location_entry_->GetRect(&formatting_rect); + RECT edit_bounds; + location_entry_->GetClientRect(&edit_bounds); + int max_edit_width = entry_width - formatting_rect.left - + (edit_bounds.right - formatting_rect.right); +#else + int max_edit_width = entry_width; +#endif + + if (max_edit_width < 0) + return; + const int available_width = AvailableWidth(max_edit_width); + bool needs_layout = force_layout; + needs_layout |= AdjustHints(available_width); + + if (!needs_layout) + return; + + // TODO(sky): baseline layout. + int location_y = TopMargin(); + int location_height = std::max(height() - location_y - kVertMargin, 0); + + // First set the bounds for the label that appears to the right of the + // security icon. + int offset = width() - kEntryPadding; + if (info_label_.IsVisible()) { + offset -= info_label_size.width(); + info_label_.SetBounds(offset, location_y, + info_label_size.width(), location_height); + offset -= kInnerPadding; + } + if (security_image_view_.IsVisible()) { + offset -= security_image_size.width(); + security_image_view_.SetBounds(offset, location_y, + security_image_size.width(), + location_height); + offset -= kInnerPadding; + } + + for (PageActionViews::const_iterator i(page_action_views_.begin()); + i != page_action_views_.end(); ++i) { + if ((*i)->IsVisible()) { + int page_action_width = (*i)->GetPreferredSize().width(); + offset -= page_action_width; + (*i)->SetBounds(offset, location_y, page_action_width, location_height); + offset -= kInnerPadding; + } + } + // We use a reverse_iterator here because we're laying out the views from + // right to left but in the vector they're ordered left to right. + for (ContentSettingViews::const_reverse_iterator + i(content_setting_views_.rbegin()); i != content_setting_views_.rend(); + ++i) { + if ((*i)->IsVisible()) { + int content_blocked_width = (*i)->GetPreferredSize().width(); + offset -= content_blocked_width; + (*i)->SetBounds(offset, location_y, content_blocked_width, + location_height); + offset -= kInnerPadding; + } + } + gfx::Rect location_bounds(kEntryPadding, location_y, entry_width, + location_height); + if (selected_keyword_view_.IsVisible()) { + LayoutView(true, &selected_keyword_view_, available_width, + &location_bounds); + } else if (keyword_hint_view_.IsVisible()) { + LayoutView(false, &keyword_hint_view_, available_width, + &location_bounds); + } else if (type_to_search_view_.IsVisible()) { + LayoutView(false, &type_to_search_view_, available_width, + &location_bounds); + } + + location_entry_view_->SetBounds(location_bounds); + if (!force_layout) { + // If force_layout is false and we got this far it means one of the views + // was added/removed or changed in size. We need to paint ourselves. + SchedulePaint(); + } +} + int LocationBarView::TopMargin() const { return std::min(kVertMargin, height()); } @@ -702,7 +669,52 @@ int LocationBarView::AvailableWidth(int location_bar_width) { } bool LocationBarView::UsePref(int pref_width, int available_width) { - return (pref_width + kViewPadding <= available_width); + return (pref_width + kInnerPadding <= available_width); +} + +bool LocationBarView::NeedsResize(View* view, int available_width) { + gfx::Size size = view->GetPreferredSize(); + if (!UsePref(size.width(), available_width)) + size = view->GetMinimumSize(); + return (view->width() != size.width()); +} + +bool LocationBarView::AdjustHints(int available_width) { + const std::wstring keyword(location_entry_->model()->keyword()); + const bool is_keyword_hint(location_entry_->model()->is_keyword_hint()); + const bool show_selected_keyword = !keyword.empty() && !is_keyword_hint; + const bool show_keyword_hint = !keyword.empty() && is_keyword_hint; + bool show_search_hint(location_entry_->model()->show_search_hint()); + DCHECK(keyword.empty() || !show_search_hint); + + if (show_search_hint) { + // Only show type to search if all the text fits. + gfx::Size view_pref = type_to_search_view_.GetPreferredSize(); + show_search_hint = UsePref(view_pref.width(), available_width); + } + + // NOTE: This isn't just one big || statement as ToggleVisibility MUST be + // invoked for each view. + bool needs_layout = false; + needs_layout |= ToggleVisibility(show_selected_keyword, + &selected_keyword_view_); + needs_layout |= ToggleVisibility(show_keyword_hint, &keyword_hint_view_); + needs_layout |= ToggleVisibility(show_search_hint, &type_to_search_view_); + if (show_selected_keyword) { + if (selected_keyword_view_.keyword() != keyword) { + needs_layout = true; + selected_keyword_view_.SetKeyword(keyword); + } + needs_layout |= NeedsResize(&selected_keyword_view_, available_width); + } else if (show_keyword_hint) { + if (keyword_hint_view_.keyword() != keyword) { + needs_layout = true; + keyword_hint_view_.SetKeyword(keyword); + } + needs_layout |= NeedsResize(&keyword_hint_view_, available_width); + } + + return needs_layout; } void LocationBarView::LayoutView(bool leading, @@ -713,20 +725,40 @@ void LocationBarView::LayoutView(bool leading, gfx::Size view_size = view->GetPreferredSize(); if (!UsePref(view_size.width(), available_width)) view_size = view->GetMinimumSize(); - if (view_size.width() + kViewPadding >= bounds->width()) { + if (view_size.width() + kInnerPadding < bounds->width()) { + view->SetVisible(true); + if (leading) { + view->SetBounds(bounds->x(), bounds->y(), view_size.width(), + bounds->height()); + bounds->Offset(view_size.width() + kInnerPadding, 0); + } else { + view->SetBounds(bounds->right() - view_size.width(), bounds->y(), + view_size.width(), bounds->height()); + } + bounds->set_width(bounds->width() - view_size.width() - kInnerPadding); + } else { view->SetVisible(false); - return; } - if (leading) { - view->SetBounds(bounds->x(), bounds->y(), view_size.width(), - bounds->height()); - bounds->Offset(view_size.width() + kViewPadding, 0); - } else { - view->SetBounds(bounds->right() - view_size.width(), bounds->y(), - view_size.width(), bounds->height()); +} + +void LocationBarView::SetSecurityIcon(ToolbarModel::Icon icon) { + switch (icon) { + case ToolbarModel::LOCK_ICON: + security_image_view_.SetImageShown(SecurityImageView::LOCK); + security_image_view_.SetVisible(true); + break; + case ToolbarModel::WARNING_ICON: + security_image_view_.SetImageShown(SecurityImageView::WARNING); + security_image_view_.SetVisible(true); + break; + case ToolbarModel::NO_ICON: + security_image_view_.SetVisible(false); + break; + default: + NOTREACHED(); + security_image_view_.SetVisible(false); + break; } - bounds->set_width(bounds->width() - view_size.width() - kViewPadding); - view->SetVisible(true); } void LocationBarView::RefreshContentSettingViews() { @@ -746,9 +778,7 @@ void LocationBarView::DeletePageActionViews() { } void LocationBarView::RefreshPageActionViews() { - if (popup_window_mode_) - return; - + std::vector page_actions; ExtensionsService* service = profile_->GetExtensionsService(); if (!service) return; @@ -760,7 +790,6 @@ void LocationBarView::RefreshPageActionViews() { // Remember the previous visibility of the page actions so that we can // notify when this changes. - std::vector page_actions; for (size_t i = 0; i < service->extensions()->size(); ++i) { if (service->extensions()->at(i)->page_action()) page_actions.push_back(service->extensions()->at(i)->page_action()); @@ -775,7 +804,8 @@ void LocationBarView::RefreshPageActionViews() { for (size_t i = 0; i < page_actions.size(); ++i) { page_action_views_[i] = new PageActionWithBadgeView( - new PageActionImageView(this, profile_, page_actions[i])); + new PageActionImageView(this, profile_, + page_actions[i], bubble_positioner_)); page_action_views_[i]->SetVisible(false); AddChildView(page_action_views_[i]); } @@ -802,6 +832,25 @@ void LocationBarView::RefreshPageActionViews() { } } +void LocationBarView::SetInfoText(const std::wstring& text, + ToolbarModel::InfoTextType text_type, + const std::wstring& tooltip_text) { + info_label_.SetVisible(!text.empty()); + info_label_.SetText(text); + if (text_type == ToolbarModel::INFO_EV_TEXT) + info_label_.SetColor(GetColor(true, SECURITY_TEXT)); + info_label_.SetTooltipText(tooltip_text); +} + +bool LocationBarView::ToggleVisibility(bool new_vis, View* view) { + DCHECK(view); + if (view->IsVisible() != new_vis) { + view->SetVisible(new_vis); + return true; + } + return false; +} + #if defined(OS_WIN) void LocationBarView::OnMouseEvent(const views::MouseEvent& event, UINT msg) { UINT flags = 0; @@ -818,54 +867,10 @@ void LocationBarView::OnMouseEvent(const views::MouseEvent& event, UINT msg) { gfx::Point screen_point(event.location()); ConvertPointToScreen(this, &screen_point); - location_entry_->HandleExternalMsg(msg, flags, screen_point.ToPOINT()); -} -#endif - -void LocationBarView::ShowFirstRunBubbleInternal( - FirstRun::BubbleType bubble_type) { -#if defined(OS_WIN) // First run bubble doesn't make sense for Chrome OS. - // If the browser is no longer active, let's not show the info bubble, as this - // would make the browser the active window again. - if (!location_entry_view_ || !location_entry_view_->GetWidget()->IsActive()) - return; - // Point at the start of the edit control; adjust to look as good as possible. - const int kXOffset = 1; // Text looks like it actually starts 1 px in. - const int kYOffset = -4; // Point into the omnibox, not just at its edge. - gfx::Point origin(location_entry_view_->bounds().x() + kXOffset, - y() + height() + kYOffset); - // If the UI layout is RTL, the coordinate system is not transformed and - // therefore we need to adjust the X coordinate so that bubble appears on the - // right hand side of the location bar. - if (UILayoutIsRightToLeft()) - origin.set_x(width() - origin.x()); - views::View::ConvertPointToScreen(this, &origin); - FirstRunBubble::Show(profile_, GetWindow(), gfx::Rect(origin, gfx::Size()), - bubble_type); -#endif + location_entry_->HandleExternalMsg(msg, flags, screen_point.ToPOINT()); } - -bool LocationBarView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) { - if (keyword_hint_view_.IsVisible() && - views::FocusManager::IsTabTraversalKeyEvent(e)) { - // We want to receive tab key events when the hint is showing. - return true; - } - -#if defined(OS_WIN) - return location_entry_->SkipDefaultKeyEventProcessing(e); -#else - // TODO(jcampan): We need to refactor the code of - // AutocompleteEditViewWin::SkipDefaultKeyEventProcessing into this class so - // it can be shared between Windows and Linux. - // For now, we just override back-space as it is the accelerator for back - // navigation. - if (e.GetKeyCode() == base::VKEY_BACK) - return true; - return false; #endif -} bool LocationBarView::GetAccessibleRole(AccessibilityTypes::Role* role) { DCHECK(role); @@ -874,213 +879,76 @@ bool LocationBarView::GetAccessibleRole(AccessibilityTypes::Role* role) { return true; } +// SelectedKeywordView ------------------------------------------------------- -void LocationBarView::WriteDragData(views::View* sender, - const gfx::Point& press_pt, - OSExchangeData* data) { - DCHECK(GetDragOperations(sender, press_pt) != DragDropTypes::DRAG_NONE); - - TabContents* tab_contents = delegate_->GetTabContents(); - DCHECK(tab_contents); - drag_utils::SetURLAndDragImage(tab_contents->GetURL(), - UTF16ToWideHack(tab_contents->GetTitle()), - tab_contents->GetFavIcon(), data); -} - -int LocationBarView::GetDragOperations(views::View* sender, - const gfx::Point& p) { - DCHECK((sender == &location_icon_view_) || (sender == &ev_bubble_view_)); - TabContents* tab_contents = delegate_->GetTabContents(); - return (tab_contents && tab_contents->GetURL().is_valid() && - !location_entry()->IsEditingOrEmpty()) ? - (DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK) : - DragDropTypes::DRAG_NONE; -} - -bool LocationBarView::CanStartDrag(View* sender, - const gfx::Point& press_pt, - const gfx::Point& p) { - return true; -} - -// ClickHandler ---------------------------------------------------------------- - -LocationBarView::ClickHandler::ClickHandler(const views::View* owner, - const LocationBarView* location_bar) - : owner_(owner), - location_bar_(location_bar) { -} - -void LocationBarView::ClickHandler::OnMouseReleased( - const views::MouseEvent& event, - bool canceled) { - if (canceled || !owner_->HitTest(event.location())) - return; - - // Do not show page info if the user has been editing the location - // bar, or the location bar is at the NTP. - if (location_bar_->location_entry()->IsEditingOrEmpty()) - return; - - TabContents* tab = location_bar_->GetTabContents(); - NavigationEntry* nav_entry = tab->controller().GetActiveEntry(); - if (!nav_entry) { - NOTREACHED(); - return; - } - tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true); -} - -// LocationIconView ------------------------------------------------------------ - -LocationBarView::LocationIconView::LocationIconView( - const LocationBarView* location_bar) - : ALLOW_THIS_IN_INITIALIZER_LIST(click_handler_(this, location_bar)) { -} - -LocationBarView::LocationIconView::~LocationIconView() { -} - -bool LocationBarView::LocationIconView::OnMousePressed( - const views::MouseEvent& event) { - // We want to show the dialog on mouse release; that is the standard behavior - // for buttons. - return true; -} - -void LocationBarView::LocationIconView::OnMouseReleased( - const views::MouseEvent& event, - bool canceled) { - click_handler_.OnMouseReleased(event, canceled); -} - -// IconLabelBubbleView --------------------------------------------------------- - -// Amount to offset the image. -static const int kImageOffset = 1; - -// Amount to offset the label from the image. -static const int kLabelOffset = 3; - -// Amount of padding after the label. -static const int kLabelPadding = 4; - -LocationBarView::IconLabelBubbleView::IconLabelBubbleView( - const int background_images[], - int contained_image, - const SkColor& color) - : background_painter_(background_images) { - AddChildView(&image_); - image_.set_parent_owned(false); - image_.SetImage( - ResourceBundle::GetSharedInstance().GetBitmapNamed(contained_image)); - AddChildView(&label_); - label_.set_parent_owned(false); - label_.SetColor(color); -} - -LocationBarView::IconLabelBubbleView::~IconLabelBubbleView() { -} - -void LocationBarView::IconLabelBubbleView::SetFont(const gfx::Font& font) { - label_.SetFont(font); -} - -void LocationBarView::IconLabelBubbleView::SetLabel(const std::wstring& label) { - label_.SetText(label); -} - -void LocationBarView::IconLabelBubbleView::Paint(gfx::Canvas* canvas) { - int y_offset = (GetParent()->height() - height()) / 2; - canvas->TranslateInt(0, y_offset); - background_painter_.Paint(width(), height(), canvas); - canvas->TranslateInt(0, -y_offset); -} - -gfx::Size LocationBarView::IconLabelBubbleView::GetPreferredSize() { - gfx::Size size(GetNonLabelSize()); - size.Enlarge(label_.GetPreferredSize().width(), 0); - return size; -} - -void LocationBarView::IconLabelBubbleView::Layout() { - image_.SetBounds(kImageOffset, 0, image_.GetPreferredSize().width(), - height()); - gfx::Size label_size(label_.GetPreferredSize()); - label_.SetBounds(image_.x() + image_.width() + kLabelOffset, - (height() - label_size.height()) / 2, label_size.width(), - label_size.height()); -} - -gfx::Size LocationBarView::IconLabelBubbleView::GetNonLabelSize() { - return gfx::Size(kImageOffset + image_.GetPreferredSize().width() + - kLabelOffset + kLabelPadding, background_painter_.height()); -} - -// EVBubbleView ---------------------------------------------------------------- - -LocationBarView::EVBubbleView::EVBubbleView(const int background_images[], - int contained_image, - const SkColor& color, - const LocationBarView* location_bar) - : IconLabelBubbleView(background_images, contained_image, color), - ALLOW_THIS_IN_INITIALIZER_LIST(click_handler_(this, location_bar)) { -} - -LocationBarView::EVBubbleView::~EVBubbleView() { -} - -bool LocationBarView::EVBubbleView::OnMousePressed( - const views::MouseEvent& event) { - // We want to show the dialog on mouse release; that is the standard behavior - // for buttons. - return true; -} +// The background is drawn using HorizontalPainter. This is the +// left/center/right image names. +static const int kBorderImages[] = { + IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_L, + IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_C, + IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_R }; -void LocationBarView::EVBubbleView::OnMouseReleased( - const views::MouseEvent& event, - bool canceled) { - click_handler_.OnMouseReleased(event, canceled); -} +// Insets around the label. +static const int kTopInset = 0; +static const int kBottomInset = 0; +static const int kLeftInset = 4; +static const int kRightInset = 4; -// SelectedKeywordView --------------------------------------------------------- +// Offset from the top the background is drawn at. +static const int kBackgroundYOffset = 2; -LocationBarView::SelectedKeywordView::SelectedKeywordView( - const int background_images[], - int contained_image, - const SkColor& color, - Profile* profile) - : IconLabelBubbleView(background_images, contained_image, color), +LocationBarView::SelectedKeywordView::SelectedKeywordView(Profile* profile) + : background_painter_(kBorderImages), profile_(profile) { + AddChildView(&full_label_); + AddChildView(&partial_label_); + // Full_label and partial_label are deleted by us, make sure View doesn't + // delete them too. + full_label_.set_parent_owned(false); + partial_label_.set_parent_owned(false); full_label_.SetVisible(false); partial_label_.SetVisible(false); + full_label_.set_border( + views::Border::CreateEmptyBorder(kTopInset, kLeftInset, kBottomInset, + kRightInset)); + partial_label_.set_border( + views::Border::CreateEmptyBorder(kTopInset, kLeftInset, kBottomInset, + kRightInset)); + full_label_.SetColor(SK_ColorBLACK); + partial_label_.SetColor(SK_ColorBLACK); } LocationBarView::SelectedKeywordView::~SelectedKeywordView() { } void LocationBarView::SelectedKeywordView::SetFont(const gfx::Font& font) { - IconLabelBubbleView::SetFont(font); full_label_.SetFont(font); partial_label_.SetFont(font); } +void LocationBarView::SelectedKeywordView::Paint(gfx::Canvas* canvas) { + canvas->TranslateInt(0, kBackgroundYOffset); + background_painter_.Paint(width(), height() - kTopInset, canvas); + canvas->TranslateInt(0, -kBackgroundYOffset); +} + gfx::Size LocationBarView::SelectedKeywordView::GetPreferredSize() { - gfx::Size size(GetNonLabelSize()); - size.Enlarge(full_label_.GetPreferredSize().width(), 0); - return size; + return full_label_.GetPreferredSize(); } gfx::Size LocationBarView::SelectedKeywordView::GetMinimumSize() { - gfx::Size size(GetNonLabelSize()); - size.Enlarge(partial_label_.GetMinimumSize().width(), 0); - return size; + return partial_label_.GetMinimumSize(); } void LocationBarView::SelectedKeywordView::Layout() { - SetLabel((width() == GetPreferredSize().width()) ? - full_label_.GetText() : partial_label_.GetText()); - IconLabelBubbleView::Layout(); + gfx::Size pref = GetPreferredSize(); + bool at_pref = (width() == pref.width()); + if (at_pref) + full_label_.SetBounds(0, 0, width(), height()); + else + partial_label_.SetBounds(0, 0, width(), height()); + full_label_.SetVisible(at_pref); + partial_label_.SetVisible(!at_pref); } void LocationBarView::SelectedKeywordView::SetKeyword( @@ -1096,9 +964,12 @@ void LocationBarView::SelectedKeywordView::SetKeyword( full_label_.SetText(l10n_util::GetStringF(IDS_OMNIBOX_KEYWORD_TEXT, short_name)); const std::wstring min_string = CalculateMinString(short_name); - partial_label_.SetText(min_string.empty() ? - full_label_.GetText() : - l10n_util::GetStringF(IDS_OMNIBOX_KEYWORD_TEXT, min_string)); + if (!min_string.empty()) { + partial_label_.SetText( + l10n_util::GetStringF(IDS_OMNIBOX_KEYWORD_TEXT, min_string)); + } else { + partial_label_.SetText(full_label_.GetText()); + } } std::wstring LocationBarView::SelectedKeywordView::CalculateMinString( @@ -1225,18 +1096,250 @@ void LocationBarView::KeywordHintView::Layout() { } } +bool LocationBarView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) { + if (keyword_hint_view_.IsVisible() && + views::FocusManager::IsTabTraversalKeyEvent(e)) { + // We want to receive tab key events when the hint is showing. + return true; + } + +#if defined(OS_WIN) + return location_entry_->SkipDefaultKeyEventProcessing(e); +#else + // TODO(jcampan): We need to refactor the code of + // AutocompleteEditViewWin::SkipDefaultKeyEventProcessing into this class so + // it can be shared between Windows and Linux. + // For now, we just override back-space as it is the accelerator for back + // navigation. + if (e.GetKeyCode() == base::VKEY_BACK) + return true; + return false; +#endif +} + +// ShowInfoBubbleTask----------------------------------------------------------- + +class LocationBarView::ShowInfoBubbleTask : public Task { + public: + explicit ShowInfoBubbleTask( + LocationBarView::LocationBarImageView* image_view); + virtual void Run(); + void Cancel(); + + private: + LocationBarView::LocationBarImageView* image_view_; + bool cancelled_; + + DISALLOW_COPY_AND_ASSIGN(ShowInfoBubbleTask); +}; + +LocationBarView::ShowInfoBubbleTask::ShowInfoBubbleTask( + LocationBarView::LocationBarImageView* image_view) + : image_view_(image_view), + cancelled_(false) { +} + +void LocationBarView::ShowInfoBubbleTask::Run() { + if (cancelled_) + return; + + if (!image_view_->GetWidget()->IsActive()) { + // The browser is no longer active. Let's not show the info bubble, this + // would make the browser the active window again. Also makes sure we NULL + // show_info_bubble_task_ to prevent the SecurityImageView from keeping a + // dangling pointer. + image_view_->show_info_bubble_task_ = NULL; + return; + } + + image_view_->ShowInfoBubble(); +} + +void LocationBarView::ShowInfoBubbleTask::Cancel() { + cancelled_ = true; +} + +// ----------------------------------------------------------------------------- + +void LocationBarView::ShowFirstRunBubbleInternal( + FirstRun::BubbleType bubble_type) { + if (!location_entry_view_) + return; + if (!location_entry_view_->GetWidget()->IsActive()) { + // The browser is no longer active. Let's not show the info bubble, this + // would make the browser the active window again. + return; + } + + gfx::Point location; + + // If the UI layout is RTL, the coordinate system is not transformed and + // therefore we need to adjust the X coordinate so that bubble appears on the + // right hand side of the location bar. + if (UILayoutIsRightToLeft()) + location.Offset(width(), 0); + views::View::ConvertPointToScreen(this, &location); + + // We try to guess that 20 pixels offset is a good place for the first + // letter in the OmniBox. + gfx::Rect bounds(location.x(), location.y(), 20, height()); + + // Moving the bounds "backwards" so that it appears within the location bar + // if the UI layout is RTL. + if (UILayoutIsRightToLeft()) + bounds.set_x(location.x() - 20); + +#if defined(OS_WIN) + FirstRunBubble::Show(profile_, GetWindow(), bounds, bubble_type); +#else + // First run bubble doesn't make sense for Chrome OS. +#endif +} + +// LocationBarImageView--------------------------------------------------------- + +LocationBarView::LocationBarImageView::LocationBarImageView( + const BubblePositioner* bubble_positioner) + : info_bubble_(NULL), + show_info_bubble_task_(NULL), + bubble_positioner_(bubble_positioner) { +} + +LocationBarView::LocationBarImageView::~LocationBarImageView() { + if (show_info_bubble_task_) + show_info_bubble_task_->Cancel(); + + if (info_bubble_) + info_bubble_->Close(); +} + +void LocationBarView::LocationBarImageView::OnMouseMoved( + const views::MouseEvent& event) { + if (show_info_bubble_task_) { + show_info_bubble_task_->Cancel(); + show_info_bubble_task_ = NULL; + } + + if (info_bubble_) { + // If an info bubble is currently showing, nothing to do. + return; + } + + show_info_bubble_task_ = new ShowInfoBubbleTask(this); + MessageLoop::current()->PostDelayedTask(FROM_HERE, show_info_bubble_task_, + kInfoBubbleHoverDelayMs); +} + +void LocationBarView::LocationBarImageView::OnMouseExited( + const views::MouseEvent& event) { + if (show_info_bubble_task_) { + show_info_bubble_task_->Cancel(); + show_info_bubble_task_ = NULL; + } + + if (info_bubble_) + info_bubble_->Close(); +} + +void LocationBarView::LocationBarImageView::InfoBubbleClosing( + InfoBubble* info_bubble, bool closed_by_escape) { + info_bubble_ = NULL; +} + +void LocationBarView::LocationBarImageView::ShowInfoBubbleImpl( + const std::wstring& text, SkColor text_color) { + gfx::Rect bounds(bubble_positioner_->GetLocationStackBounds()); + gfx::Point location; + views::View::ConvertPointToScreen(this, &location); + bounds.set_x(location.x()); + bounds.set_width(width()); + + views::Label* label = new views::Label(text); + label->SetMultiLine(true); + label->SetColor(text_color); + label->SetFont(ResourceBundle::GetSharedInstance().GetFont( + ResourceBundle::BaseFont).DeriveFont(2)); + label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + label->SizeToFit(0); + DCHECK(info_bubble_ == NULL); + info_bubble_ = InfoBubble::Show(GetWindow(), bounds, label, this); + show_info_bubble_task_ = NULL; +} + +// SecurityImageView------------------------------------------------------------ + +// static +SkBitmap* LocationBarView::SecurityImageView::lock_icon_ = NULL; +SkBitmap* LocationBarView::SecurityImageView::warning_icon_ = NULL; + +LocationBarView::SecurityImageView::SecurityImageView( + const LocationBarView* parent, + Profile* profile, + ToolbarModel* model, + const BubblePositioner* bubble_positioner) + : LocationBarImageView(bubble_positioner), + parent_(parent), + profile_(profile), + model_(model) { + if (!lock_icon_) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + lock_icon_ = rb.GetBitmapNamed(IDR_LOCK); + warning_icon_ = rb.GetBitmapNamed(IDR_WARNING); + } + SetImageShown(LOCK); +} + +LocationBarView::SecurityImageView::~SecurityImageView() { +} + +void LocationBarView::SecurityImageView::SetImageShown(Image image) { + switch (image) { + case LOCK: + SetImage(lock_icon_); + break; + case WARNING: + SetImage(warning_icon_); + break; + default: + NOTREACHED(); + break; + } +} + +bool LocationBarView::SecurityImageView::OnMousePressed( + const views::MouseEvent& event) { + TabContents* tab = parent_->GetTabContents(); + NavigationEntry* nav_entry = tab->controller().GetActiveEntry(); + if (!nav_entry) { + NOTREACHED(); + return true; + } + tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true); + return true; +} + +void LocationBarView::SecurityImageView::ShowInfoBubble() { + std::wstring text; + model_->GetIconHoverText(&text); + ShowInfoBubbleImpl(text, GetColor( + model_->GetSecurityLevel() == ToolbarModel::SECURE, + SECURITY_INFO_BUBBLE_TEXT)); +} + // ContentSettingImageView------------------------------------------------------ LocationBarView::ContentSettingImageView::ContentSettingImageView( ContentSettingsType content_type, const LocationBarView* parent, - Profile* profile) + Profile* profile, + const BubblePositioner* bubble_positioner) : content_setting_image_model_( ContentSettingImageModel::CreateContentSettingImageModel( content_type)), parent_(parent), profile_(profile), - info_bubble_(NULL) { + info_bubble_(NULL), + bubble_positioner_(bubble_positioner) { } LocationBarView::ContentSettingImageView::~ContentSettingImageView() { @@ -1248,39 +1351,29 @@ void LocationBarView::ContentSettingImageView::UpdateFromTabContents( const TabContents* tab_contents) { int old_icon = content_setting_image_model_->get_icon(); content_setting_image_model_->UpdateFromTabContents(tab_contents); - if (!content_setting_image_model_->is_visible()) { + if (content_setting_image_model_->is_visible()) { + if (old_icon != content_setting_image_model_->get_icon()) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + SetImage(rb.GetBitmapNamed(content_setting_image_model_->get_icon())); + } + SetTooltipText(UTF8ToWide(content_setting_image_model_->get_tooltip())); + SetVisible(true); + } else { SetVisible(false); - return; - } - if (old_icon != content_setting_image_model_->get_icon()) { - SetImage(ResourceBundle::GetSharedInstance().GetBitmapNamed( - content_setting_image_model_->get_icon())); } - SetTooltipText(UTF8ToWide(content_setting_image_model_->get_tooltip())); - SetVisible(true); } bool LocationBarView::ContentSettingImageView::OnMousePressed( const views::MouseEvent& event) { - // We want to show the bubble on mouse release; that is the standard behavior - // for buttons. - return true; -} - -void LocationBarView::ContentSettingImageView::OnMouseReleased( - const views::MouseEvent& event, - bool canceled) { - if (canceled || !HitTest(event.location())) - return; + gfx::Rect bounds(bubble_positioner_->GetLocationStackBounds()); + gfx::Point location; + views::View::ConvertPointToScreen(this, &location); + bounds.set_x(location.x()); + bounds.set_width(width()); TabContents* tab_contents = parent_->GetTabContents(); if (!tab_contents) - return; - - gfx::Rect screen_bounds(GetImageBounds()); - gfx::Point origin(screen_bounds.origin()); - views::View::ConvertPointToScreen(this, &origin); - screen_bounds.set_origin(origin); + return true; ContentSettingBubbleContents* bubble_contents = new ContentSettingBubbleContents( ContentSettingBubbleModel::CreateContentSettingBubbleModel( @@ -1288,9 +1381,9 @@ void LocationBarView::ContentSettingImageView::OnMouseReleased( content_setting_image_model_->get_content_settings_type()), profile_, tab_contents); DCHECK(!info_bubble_); - info_bubble_ = - InfoBubble::Show(GetWindow(), screen_bounds, bubble_contents, this); + info_bubble_ = InfoBubble::Show(GetWindow(), bounds, bubble_contents, this); bubble_contents->set_info_bubble(info_bubble_); + return true; } void LocationBarView::ContentSettingImageView::VisibilityChanged( @@ -1315,8 +1408,10 @@ bool LocationBarView::ContentSettingImageView::CloseOnEscape() { LocationBarView::PageActionImageView::PageActionImageView( LocationBarView* owner, Profile* profile, - ExtensionAction* page_action) - : owner_(owner), + ExtensionAction* page_action, + const BubblePositioner* bubble_positioner) + : LocationBarImageView(bubble_positioner), + owner_(owner), profile_(profile), page_action_(page_action), ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), @@ -1373,17 +1468,19 @@ void LocationBarView::PageActionImageView::ExecuteAction(int button, if (popup_showing) return; - gfx::Rect screen_bounds(GetImageBounds()); - gfx::Point origin(screen_bounds.origin()); - View::ConvertPointToScreen(this, &origin); - screen_bounds.set_origin(origin); + View* parent = GetParent(); + gfx::Point origin; + View::ConvertPointToScreen(parent, &origin); + gfx::Rect rect = parent->bounds(); + rect.set_x(origin.x()); + rect.set_y(origin.y()); popup_ = ExtensionPopup::Show( page_action_->GetPopupUrl(current_tab_id_), browser, browser->profile(), browser->window()->GetNativeHandle(), - screen_bounds, + rect, BubbleBorder::TOP_RIGHT, true, // Activate the popup window. inspect_with_devtools, @@ -1396,17 +1493,24 @@ void LocationBarView::PageActionImageView::ExecuteAction(int button, } } +void LocationBarView::PageActionImageView::OnMouseMoved( + const views::MouseEvent& event) { + // PageActionImageView uses normal tooltips rather than the info bubble, + // so just do nothing here rather than letting LocationBarImageView start + // its hover timer. +} + bool LocationBarView::PageActionImageView::OnMousePressed( const views::MouseEvent& event) { - // We want to show the bubble on mouse release; that is the standard behavior - // for buttons. (Also, triggering on mouse press causes bugs like - // http://crbug.com/33155.) + // We are interested in capturing mouse messages, but we want want to wait + // until mouse-up because we might show a context menu. Doing so on mouse-down + // causes weird bugs like http://crbug.com/33155. return true; } void LocationBarView::PageActionImageView::OnMouseReleased( const views::MouseEvent& event, bool canceled) { - if (canceled || !HitTest(event.location())) + if (canceled) return; int button = -1; @@ -1416,26 +1520,30 @@ void LocationBarView::PageActionImageView::OnMouseReleased( button = 2; } else if (event.IsRightMouseButton()) { // Get the top left point of this button in screen coordinates. - gfx::Point menu_origin; - ConvertPointToScreen(this, &menu_origin); + gfx::Point point = gfx::Point(0, 0); + ConvertPointToScreen(this, &point); // Make the menu appear below the button. - menu_origin.Offset(0, height()); + point.Offset(0, height()); Extension* extension = profile_->GetExtensionsService()->GetExtensionById( page_action()->extension_id(), false); Browser* browser = BrowserView::GetBrowserViewForNativeWindow( platform_util::GetTopLevel(GetWidget()->GetNativeView()))->browser(); - context_menu_contents_ = - new ExtensionContextMenuModel(extension, browser, this); + context_menu_contents_ = new ExtensionContextMenuModel( + extension, browser, this); context_menu_menu_.reset(new views::Menu2(context_menu_contents_.get())); - context_menu_menu_->RunContextMenuAt(menu_origin); + context_menu_menu_->RunContextMenuAt(point); return; } ExecuteAction(button, false); // inspect_with_devtools } +void LocationBarView::PageActionImageView::ShowInfoBubble() { + ShowInfoBubbleImpl(ASCIIToWide(tooltip_), GetColor(false, TEXT)); +} + void LocationBarView::PageActionImageView::OnImageLoaded( SkBitmap* image, ExtensionResource resource, int index) { // We loaded icons()->size() icons, plus one extra if the page action had @@ -1464,8 +1572,8 @@ void LocationBarView::PageActionImageView::UpdateVisibility( current_tab_id_ = ExtensionTabUtil::GetTabId(contents); current_url_ = url; - bool visible = - preview_enabled_ || page_action_->GetIsVisible(current_tab_id_); + bool visible = preview_enabled_ || + page_action_->GetIsVisible(current_tab_id_); if (visible) { // Set the tooltip. tooltip_ = page_action_->GetTitle(current_tab_id_); @@ -1521,54 +1629,6 @@ void LocationBarView::PageActionImageView::HidePopup() { popup_->Close(); } -// StarView--------------------------------------------------------------------- - -LocationBarView::StarView::StarView(CommandUpdater* command_updater) - : command_updater_(command_updater) { - SetID(VIEW_ID_STAR_BUTTON); - SetToggled(false); -} - -LocationBarView::StarView::~StarView() { -} - -void LocationBarView::StarView::SetToggled(bool on) { - SetTooltipText(l10n_util::GetString( - on ? IDS_TOOLTIP_STARRED : IDS_TOOLTIP_STAR)); - // Since StarView is an ImageView, the SetTooltipText changes the accessible - // name. To keep the accessible name unchanged, we need to set the accessible - // name right after we modify the tooltip text for this view. - SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_STAR)); - SetImage(ResourceBundle::GetSharedInstance().GetBitmapNamed( - on ? IDR_OMNIBOX_STAR_LIT : IDR_OMNIBOX_STAR)); -} - -bool LocationBarView::StarView::GetAccessibleRole( - AccessibilityTypes::Role* role) { - *role = AccessibilityTypes::ROLE_PUSHBUTTON; - return true; -} - -bool LocationBarView::StarView::OnMousePressed(const views::MouseEvent& event) { - // We want to show the bubble on mouse release; that is the standard behavior - // for buttons. - return true; -} - -void LocationBarView::StarView::OnMouseReleased(const views::MouseEvent& event, - bool canceled) { - if (!canceled && HitTest(event.location())) - command_updater_->ExecuteCommand(IDC_BOOKMARK_PAGE); -} - -void LocationBarView::StarView::InfoBubbleClosing(InfoBubble* info_bubble, - bool closed_by_escape) { -} - -bool LocationBarView::StarView::CloseOnEscape() { - return true; -} - //////////////////////////////////////////////////////////////////////////////// // LocationBarView, LocationBar implementation: diff --git a/chrome/browser/views/location_bar_view.h b/chrome/browser/views/location_bar_view.h index 956523b..faf2bfc 100644 --- a/chrome/browser/views/location_bar_view.h +++ b/chrome/browser/views/location_bar_view.h @@ -38,6 +38,7 @@ #endif class Browser; +class BubblePositioner; class CommandUpdater; class ContentSettingImageModel; class ExtensionAction; @@ -56,7 +57,6 @@ class Profile; class LocationBarView : public LocationBar, public LocationBarTesting, public views::View, - public views::DragController, public AutocompleteEditController { public: class Delegate { @@ -76,13 +76,17 @@ class LocationBarView : public LocationBar, SELECTED_TEXT, DEEMPHASIZED_TEXT, SECURITY_TEXT, + SECURITY_INFO_BUBBLE_TEXT, + SCHEME_STRIKEOUT, + NUM_KINDS }; LocationBarView(Profile* profile, CommandUpdater* command_updater, ToolbarModel* model, Delegate* delegate, - bool popup_window_mode); + bool popup_window_mode, + const BubblePositioner* bubble_positioner); virtual ~LocationBarView(); void Init(); @@ -93,8 +97,7 @@ class LocationBarView : public LocationBar, // Returns the appropriate color for the desired kind, based on the user's // system theme. - static SkColor GetColor(ToolbarModel::SecurityLevel security_level, - ColorKind kind); + static SkColor GetColor(bool is_secure, ColorKind kind); // Updates the location bar. We also reset the bar's permanent text and // security style, and, if |tab_for_state_restoring| is non-NULL, also restore @@ -118,12 +121,6 @@ class LocationBarView : public LocationBar, // Retrieves the PageAction View which is associated with |page_action|. views::View* GetPageActionView(ExtensionAction* page_action); - // Toggles the star on or off. - void SetStarToggled(bool on); - - // Shows the bookmark bubble. - void ShowStarBubble(const GURL& url, bool newly_bookmarked); - // Sizing functions virtual gfx::Size GetPreferredSize(); @@ -161,15 +158,6 @@ class LocationBarView : public LocationBar, virtual bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e); virtual bool GetAccessibleRole(AccessibilityTypes::Role* role); - // Overridden from views::DragController: - virtual void WriteDragData(View* sender, - const gfx::Point& press_pt, - OSExchangeData* data); - virtual int GetDragOperations(View* sender, const gfx::Point& p); - virtual bool CanStartDrag(View* sender, - const gfx::Point& press_pt, - const gfx::Point& p); - // Overridden from LocationBar: virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type); virtual std::wstring GetInputString() const; @@ -184,9 +172,6 @@ class LocationBarView : public LocationBar, virtual void InvalidatePageActions(); virtual void SaveStateToContents(TabContents* contents); virtual void Revert(); - virtual const AutocompleteEditView* location_entry() const { - return location_entry_.get(); - } virtual AutocompleteEditView* location_entry() { return location_entry_.get(); } @@ -205,100 +190,20 @@ class LocationBarView : public LocationBar, void Focus(); private: - // This helper class is kept as a member by classes that need to show the Page - // Info dialog on click, to encapsulate that logic in one place. - class ClickHandler { - public: - explicit ClickHandler(const views::View* owner, - const LocationBarView* location_bar); - - void OnMouseReleased(const views::MouseEvent& event, bool canceled); - - private: - const views::View* owner_; - const LocationBarView* location_bar_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(ClickHandler); - }; - - // LocationIconView is used to display an icon to the left of the edit field. - // This shows the user's current action while editing, the page security - // status on https pages, or a globe for other URLs. - class LocationIconView : public views::ImageView { - public: - explicit LocationIconView(const LocationBarView* location_bar); - virtual ~LocationIconView(); - - // Overridden from view. - virtual bool OnMousePressed(const views::MouseEvent& event); - virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled); - - private: - ClickHandler click_handler_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(LocationIconView); - }; - - // View used to draw a bubble to the left of the address, containing an icon - // and a label. We use this as a base for the classes that handle the EV - // bubble and tab-to-search UI. - class IconLabelBubbleView : public views::View { + // View used when the user has selected a keyword. + // + // SelectedKeywordView maintains two labels. One label contains the + // complete description of the keyword, the second contains a truncated + // version of the description. The second is used if there is not enough room + // to display the complete description. + class SelectedKeywordView : public views::View { public: - IconLabelBubbleView(const int background_images[], - int contained_image, - const SkColor& color); - virtual ~IconLabelBubbleView(); + explicit SelectedKeywordView(Profile* profile); + virtual ~SelectedKeywordView(); void SetFont(const gfx::Font& font); - void SetLabel(const std::wstring& label); virtual void Paint(gfx::Canvas* canvas); - virtual gfx::Size GetPreferredSize(); - virtual void Layout(); - - protected: - gfx::Size GetNonLabelSize(); - - private: - // For painting the background. - views::HorizontalPainter background_painter_; - - // The contents of the bubble. - views::ImageView image_; - views::Label label_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(IconLabelBubbleView); - }; - - // EVBubbleView displays the EV Bubble. - class EVBubbleView : public IconLabelBubbleView { - public: - EVBubbleView(const int background_images[], - int contained_image, - const SkColor& color, - const LocationBarView* location_bar); - virtual ~EVBubbleView(); - - // Overridden from view. - virtual bool OnMousePressed(const views::MouseEvent& event); - virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled); - - private: - ClickHandler click_handler_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(EVBubbleView); - }; - - // SelectedKeywordView displays the tab-to-search UI. - class SelectedKeywordView : public IconLabelBubbleView { - public: - SelectedKeywordView(const int background_images[], - int contained_image, - const SkColor& color, - Profile* profile); - virtual ~SelectedKeywordView(); - - void SetFont(const gfx::Font& font); virtual gfx::Size GetPreferredSize(); virtual gfx::Size GetMinimumSize(); @@ -319,16 +224,18 @@ class LocationBarView : public LocationBar, // deleted out from under us. std::wstring keyword_; - // These labels are never visible. They are used to size the view. One - // label contains the complete description of the keyword, the second - // contains a truncated version of the description, for if there is not - // enough room to display the complete description. + // For painting the background. + views::HorizontalPainter background_painter_; + + // Label containing the complete description. views::Label full_label_; + + // Label containing the partial description. views::Label partial_label_; Profile* profile_; - DISALLOW_IMPLICIT_CONSTRUCTORS(SelectedKeywordView); + DISALLOW_COPY_AND_ASSIGN(SelectedKeywordView); }; // KeywordHintView is used to display a hint to the user when the selected @@ -368,7 +275,96 @@ class LocationBarView : public LocationBar, Profile* profile_; - DISALLOW_IMPLICIT_CONSTRUCTORS(KeywordHintView); + DISALLOW_COPY_AND_ASSIGN(KeywordHintView); + }; + + class ShowInfoBubbleTask; + class ShowFirstRunBubbleTask; + + class LocationBarImageView : public views::ImageView, + public InfoBubbleDelegate { + public: + explicit LocationBarImageView(const BubblePositioner* bubble_positioner); + virtual ~LocationBarImageView(); + + // Overridden from view for the mouse hovering. + virtual void OnMouseMoved(const views::MouseEvent& event); + virtual void OnMouseExited(const views::MouseEvent& event); + virtual bool OnMousePressed(const views::MouseEvent& event) = 0; + + // InfoBubbleDelegate + void InfoBubbleClosing(InfoBubble* info_bubble, bool closed_by_escape); + bool CloseOnEscape() { return true; } + + virtual void ShowInfoBubble() = 0; + + protected: + void ShowInfoBubbleImpl(const std::wstring& text, SkColor text_color); + + private: + friend class ShowInfoBubbleTask; + + // The currently shown info bubble if any. + InfoBubble* info_bubble_; + + // A task used to display the info bubble when the mouse hovers on the + // image. + ShowInfoBubbleTask* show_info_bubble_task_; + + // A positioner used to give the info bubble the correct target bounds. The + // caller maintains ownership of this and must ensure it's kept alive. + const BubblePositioner* bubble_positioner_; + + DISALLOW_COPY_AND_ASSIGN(LocationBarImageView); + }; + + // SecurityImageView is used to display the lock or warning icon when the + // current URL's scheme is https. + // + // If a message has been set with SetInfoBubbleText, it displays an info + // bubble when the mouse hovers on the image. + class SecurityImageView : public LocationBarImageView { + public: + enum Image { + LOCK = 0, + WARNING + }; + + SecurityImageView(const LocationBarView* parent, + Profile* profile, + ToolbarModel* model_, + const BubblePositioner* bubble_positioner); + virtual ~SecurityImageView(); + + // Sets the image that should be displayed. + void SetImageShown(Image image); + + // Overridden from view for the mouse hovering. + virtual bool OnMousePressed(const views::MouseEvent& event); + + void set_profile(Profile* profile) { profile_ = profile; } + + virtual void ShowInfoBubble(); + + private: + // The lock icon shown when using HTTPS. + static SkBitmap* lock_icon_; + + // The warning icon shown when HTTPS is broken. + static SkBitmap* warning_icon_; + + // A task used to display the info bubble when the mouse hovers on the + // image. + ShowInfoBubbleTask* show_info_bubble_task_; + + // The owning LocationBarView. + const LocationBarView* parent_; + + Profile* profile_; + + ToolbarModel* model_; + + DISALLOW_COPY_AND_ASSIGN(SecurityImageView); }; class ContentSettingImageView : public views::ImageView, @@ -376,7 +372,8 @@ class LocationBarView : public LocationBar, public: ContentSettingImageView(ContentSettingsType content_type, const LocationBarView* parent, - Profile* profile); + Profile* profile, + const BubblePositioner* bubble_positioner); virtual ~ContentSettingImageView(); void set_profile(Profile* profile) { profile_ = profile; } @@ -385,7 +382,6 @@ class LocationBarView : public LocationBar, private: // views::ImageView overrides: virtual bool OnMousePressed(const views::MouseEvent& event); - virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled); virtual void VisibilityChanged(View* starting_from, bool is_visible); // InfoBubbleDelegate overrides: @@ -404,20 +400,25 @@ class LocationBarView : public LocationBar, // The currently shown info bubble if any. InfoBubble* info_bubble_; + // A positioner used to give the info bubble the correct target bounds. The + // caller maintains ownership of this and must ensure it's kept alive. + const BubblePositioner* bubble_positioner_; + DISALLOW_IMPLICIT_CONSTRUCTORS(ContentSettingImageView); }; typedef std::vector ContentSettingViews; // PageActionImageView is used to display the icon for a given PageAction // and notify the extension when the icon is clicked. - class PageActionImageView : public views::ImageView, + class PageActionImageView : public LocationBarImageView, public ImageLoadingTracker::Observer, public ExtensionContextMenuModel::PopupDelegate, public ExtensionPopup::Observer { public: PageActionImageView(LocationBarView* owner, Profile* profile, - ExtensionAction* page_action); + ExtensionAction* page_action, + const BubblePositioner* bubble_positioner); virtual ~PageActionImageView(); ExtensionAction* page_action() { return page_action_; } @@ -429,9 +430,13 @@ class LocationBarView : public LocationBar, } // Overridden from view. + virtual void OnMouseMoved(const views::MouseEvent& event); virtual bool OnMousePressed(const views::MouseEvent& event); virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled); + // Overridden from LocationBarImageView. + virtual void ShowInfoBubble(); + // Overridden from ImageLoadingTracker. virtual void OnImageLoaded( SkBitmap* image, ExtensionResource resource, int index); @@ -492,7 +497,7 @@ class LocationBarView : public LocationBar, // The current popup and the button it came from. NULL if no popup. ExtensionPopup* popup_; - DISALLOW_IMPLICIT_CONSTRUCTORS(PageActionImageView); + DISALLOW_COPY_AND_ASSIGN(PageActionImageView); }; friend class PageActionImageView; @@ -500,30 +505,11 @@ class LocationBarView : public LocationBar, friend class PageActionWithBadgeView; typedef std::vector PageActionViews; - class StarView : public views::ImageView, public InfoBubbleDelegate { - public: - explicit StarView(CommandUpdater* command_updater); - virtual ~StarView(); - - // Toggles the star on or off. - void SetToggled(bool on); - - private: - // views::ImageView overrides: - virtual bool GetAccessibleRole(AccessibilityTypes::Role* role); - virtual bool OnMousePressed(const views::MouseEvent& event); - virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled); - - // InfoBubbleDelegate overrides: - virtual void InfoBubbleClosing(InfoBubble* info_bubble, - bool closed_by_escape); - virtual bool CloseOnEscape(); - - // The CommandUpdater for the Browser object that owns the location bar. - CommandUpdater* command_updater_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(StarView); - }; + // Both Layout and OnChanged call into this. This updates the contents + // of the 3 views: selected_keyword, keyword_hint and type_search_view. If + // force_layout is true, or one of these views has changed in such a way as + // to necessitate a layout, layout occurs as well. + void DoLayout(bool force_layout); // Returns the height in pixels of the margin at the top of the bar. int TopMargin() const; @@ -539,12 +525,25 @@ class LocationBarView : public LocationBar, // minimum size of the view should be used. bool UsePref(int pref_width, int available_width); + // Returns true if the view needs to be resized. This determines whether the + // min or pref should be used, and returns true if the view is not at that + // size. + bool NeedsResize(View* view, int available_width); + + // Adjusts the keyword hint, selected keyword and type to search views + // based on the contents of the edit. Returns true if something changed that + // necessitates a layout. + bool AdjustHints(int available_width); + // If View fits in the specified region, it is made visible and the // bounds are adjusted appropriately. If the View does not fit, it is // made invisible. void LayoutView(bool leading, views::View* view, int available_width, gfx::Rect* bounds); + // Sets the security icon to display. Note that no repaint is done. + void SetSecurityIcon(ToolbarModel::Icon icon); + // Update the visibility state of the Content Blocked icons to reflect what is // actually blocked on the current page. void RefreshContentSettingViews(); @@ -556,8 +555,16 @@ class LocationBarView : public LocationBar, // PageActions. void RefreshPageActionViews(); - // Sets the visibility of view to new_vis. - void ToggleVisibility(bool new_vis, views::View* view); + // Sets the text that should be displayed in the info label and its associated + // tooltip text. Call with an empty string if the info label should be + // hidden. + void SetInfoText(const std::wstring& text, + ToolbarModel::InfoTextType text_type, + const std::wstring& tooltip_text); + + // Sets the visibility of view to new_vis. Returns whether the visibility + // changed. + bool ToggleVisibility(bool new_vis, views::View* view); #if defined(OS_WIN) // Helper for the Mouse event handlers that does all the real work. @@ -602,20 +609,13 @@ class LocationBarView : public LocationBar, // Font used by edit and some of the hints. gfx::Font font_; - // An icon to the left of the edit field. - LocationIconView location_icon_view_; - - // A bubble displayed for EV HTTPS sites. - EVBubbleView ev_bubble_view_; - // Location_entry view wrapper views::NativeViewHost* location_entry_view_; // The following views are used to provide hints and remind the user as to // what is going in the edit. They are all added a children of the // LocationBarView. At most one is visible at a time. Preference is - // given to the keyword_view_, then hint_view_. - // These autocollapse when the edit needs the room. + // given to the keyword_view_, then hint_view_, then type_to_search_view_. // Shown if the user has selected a keyword. SelectedKeywordView selected_keyword_view_; @@ -623,14 +623,20 @@ class LocationBarView : public LocationBar, // Shown if the selected url has a corresponding keyword. KeywordHintView keyword_hint_view_; + // Shown if the text is not a keyword or url. + views::Label type_to_search_view_; + + // The view that shows the lock/warning when in HTTPS mode. + SecurityImageView security_image_view_; + // The content setting views. ContentSettingViews content_setting_views_; // The page action icon views. PageActionViews page_action_views_; - // The star. - StarView star_view_; + // A label displayed after the lock icon to show some extra information. + views::Label info_label_; // When true, the location bar view is read only and also is has a slightly // different presentation (font size / color). This is used for popups. @@ -639,10 +645,13 @@ class LocationBarView : public LocationBar, // Used schedule a task for the first run info bubble. ScopedRunnableMethodFactory first_run_bubble_; + // The positioner that places the omnibox and info bubbles. + const BubblePositioner* bubble_positioner_; + // Storage of string needed for accessibility. std::wstring accessible_name_; - DISALLOW_IMPLICIT_CONSTRUCTORS(LocationBarView); + DISALLOW_COPY_AND_ASSIGN(LocationBarView); }; #endif // CHROME_BROWSER_VIEWS_LOCATION_BAR_VIEW_H_ diff --git a/chrome/browser/views/pinned_contents_info_bubble.cc b/chrome/browser/views/pinned_contents_info_bubble.cc deleted file mode 100644 index 8331db1..0000000 --- a/chrome/browser/views/pinned_contents_info_bubble.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/views/pinned_contents_info_bubble.h" - -#include "chrome/browser/views/bubble_border.h" - -#if defined(OS_WIN) -// BorderWidget --------------------------------------------------------------- - -void PinnedContentsBorderContents::InitAndGetBounds( - const gfx::Rect& position_relative_to, - const gfx::Size& contents_size, - bool prefer_arrow_on_right, - gfx::Rect* contents_bounds, - gfx::Rect* window_bounds) { - bubble_border_ = new BubbleBorder; - - // Arrow offset is calculated from the middle of the |position_relative_to|. - int offset = position_relative_to.x() + (position_relative_to.width() / 2); - offset -= bubble_anchor_.x(); - - gfx::Insets insets; - bubble_border_->GetInsets(&insets); - offset += kLeftMargin + insets.left() + 1; - bubble_border_->set_arrow_offset(offset); - - BorderContents::InitAndGetBounds( - position_relative_to, contents_size, prefer_arrow_on_right, - contents_bounds, window_bounds); - - // Now move the y position to make sure the bubble contents overlap the view. - window_bounds->Offset(0, -(kTopMargin + 1)); -} - -gfx::Rect PinnedContentsBorderWidget::InitAndGetBounds( - HWND owner, - const gfx::Rect& position_relative_to, - const gfx::Size& contents_size, - bool prefer_arrow_on_right) { - border_contents_ = new PinnedContentsBorderContents(bubble_anchor_); - return BorderWidget::InitAndGetBounds( - owner, position_relative_to, contents_size, - prefer_arrow_on_right); -} -#endif - -// InfoBubble ----------------------------------------------------------------- - -// static -PinnedContentsInfoBubble* PinnedContentsInfoBubble::Show( - views::Window* parent, - const gfx::Rect& position_relative_to, - const gfx::Point& bubble_anchor, - views::View* contents, - InfoBubbleDelegate* delegate) { - PinnedContentsInfoBubble* window = - new PinnedContentsInfoBubble(bubble_anchor); - window->Init(parent, position_relative_to, contents, delegate); - return window; -} - -void PinnedContentsInfoBubble::Init(views::Window* parent, - const gfx::Rect& position_relative_to, - views::View* contents, - InfoBubbleDelegate* delegate) { -// TODO(finnur): This needs to be implemented for other platforms once we -// decide this is the way to go. -#if defined(OS_WIN) - border_.reset(new PinnedContentsBorderWidget(bubble_anchor_)); -#endif - InfoBubble::Init(parent, position_relative_to, contents, delegate); -} diff --git a/chrome/browser/views/pinned_contents_info_bubble.h b/chrome/browser/views/pinned_contents_info_bubble.h deleted file mode 100644 index 92477c0..0000000 --- a/chrome/browser/views/pinned_contents_info_bubble.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIEWS_PINNED_CONTENTS_INFO_BUBBLE_H_ -#define CHROME_BROWSER_VIEWS_PINNED_CONTENTS_INFO_BUBBLE_H_ - -#include "chrome/browser/views/info_bubble.h" - -// This is a specialization of BorderContents, used to draw a border around -// an InfoBubble that has its contents pinned to a specific location. See -// base class for details. -class PinnedContentsBorderContents : public BorderContents { - public: - explicit PinnedContentsBorderContents(const gfx::Point& bubble_anchor) - : bubble_anchor_(bubble_anchor) {} - - // BorderContents overrides: - virtual void InitAndGetBounds( - const gfx::Rect& position_relative_to, // In screen coordinates - const gfx::Size& contents_size, - bool prefer_arrow_on_right, - gfx::Rect* contents_bounds, // Returned in window coordinates - gfx::Rect* window_bounds); // Returned in screen coordinates - - private: - // The location of the pinned contents (in screen coordinates). - const gfx::Point bubble_anchor_; - - DISALLOW_COPY_AND_ASSIGN(PinnedContentsBorderContents); -}; - -#if defined(OS_WIN) -// The window that surrounds the info bubble. See base class for details. -class PinnedContentsBorderWidget : public BorderWidget { - public: - explicit PinnedContentsBorderWidget(const gfx::Point& bubble_anchor) - : bubble_anchor_(bubble_anchor) {} - virtual ~PinnedContentsBorderWidget() {} - - // BorderWidget overrides: - virtual gfx::Rect InitAndGetBounds(HWND owner, - const gfx::Rect& position_relative_to, - const gfx::Size& contents_size, - bool is_rtl); - - private: - // The location of the pinned contents (in screen coordinates). - const gfx::Point bubble_anchor_; - - DISALLOW_COPY_AND_ASSIGN(PinnedContentsBorderWidget); -}; -#endif - -// A specialization of the InfoBubble. Used to draw an InfoBubble which, in -// addition to having an arrow pointing to where the user clicked, also shifts -// the bubble horizontally to fix it to a specific location. See base class -// for details. -class PinnedContentsInfoBubble : public InfoBubble { - public: - // Shows the InfoBubble (see base class function for details). - // |bubble_anchor| specifies how far horizontally to shift the bubble in - // order to anchor its contents. Once the InfoBubble has been anchored its - // arrow may be pointing to a slightly different |y| location than specified - // in |position_relative_to|. - static PinnedContentsInfoBubble* Show(views::Window* parent, - const gfx::Rect& position_relative_to, - const gfx::Point& bubble_anchor_, - views::View* contents, - InfoBubbleDelegate* delegate); - - private: - explicit PinnedContentsInfoBubble(const gfx::Point& bubble_anchor) - : bubble_anchor_(bubble_anchor) {} - virtual ~PinnedContentsInfoBubble() {} - - // InfoBubble overrides: - virtual void Init(views::Window* parent, - const gfx::Rect& position_relative_to, - views::View* contents, - InfoBubbleDelegate* delegate); - - // The location of the pinned contents (in screen coordinates). - const gfx::Point bubble_anchor_; - - DISALLOW_COPY_AND_ASSIGN(PinnedContentsInfoBubble); -}; - -#endif // CHROME_BROWSER_VIEWS_PINNED_CONTENTS_INFO_BUBBLE_H_ diff --git a/chrome/browser/views/tabs/dragged_tab_controller.cc b/chrome/browser/views/tabs/dragged_tab_controller.cc index 3521a88..ce26ac7 100644 --- a/chrome/browser/views/tabs/dragged_tab_controller.cc +++ b/chrome/browser/views/tabs/dragged_tab_controller.cc @@ -316,7 +316,7 @@ DraggedTabController::DraggedTabController(Tab* source_tab, original_delegate_(NULL), source_tab_(source_tab), source_tabstrip_(source_tabstrip), - source_model_index_(source_tabstrip->GetModelIndexOfTab(source_tab)), + source_model_index_(source_tabstrip->GetIndexOfTab(source_tab)), attached_tabstrip_(source_tabstrip), old_focused_view_(NULL), in_destructor_(false), @@ -508,7 +508,7 @@ void DraggedTabController::InitWindowCreatePoint() { // first_tab based on source_tabstrip_, not attached_tabstrip_. Otherwise, // the window_create_point_ is not in the correct coordinate system. Please // refer to http://crbug.com/6223 comment #15 for detailed information. - Tab* first_tab = source_tabstrip_->GetTabAtTabDataIndex(0); + Tab* first_tab = source_tabstrip_->GetTabAt(0); views::View::ConvertPointToWidget(first_tab, &first_source_tab_point_); UpdateWindowCreatePoint(); } @@ -963,9 +963,8 @@ gfx::Point DraggedTabController::GetDraggedViewPoint( Tab* DraggedTabController::GetTabMatchingDraggedContents( TabStrip* tabstrip) const { - int model_index = tabstrip->model()->GetIndexOfTabContents(dragged_contents_); - return model_index == TabStripModel::kNoTab ? - NULL : tabstrip->GetTabAtModelIndex(model_index); + int index = tabstrip->model()->GetIndexOfTabContents(dragged_contents_); + return index == TabStripModel::kNoTab ? NULL : tabstrip->GetTabAt(index); } bool DraggedTabController::EndDragImpl(EndDragType type) { diff --git a/chrome/browser/views/tabs/tab_renderer.cc b/chrome/browser/views/tabs/tab_renderer.cc index f089393..b363cb5 100644 --- a/chrome/browser/views/tabs/tab_renderer.cc +++ b/chrome/browser/views/tabs/tab_renderer.cc @@ -6,7 +6,6 @@ #include -#include "app/animation_container.h" #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "app/slide_animation.h" @@ -82,15 +81,9 @@ static int loading_animation_frame_count = 0; static int waiting_animation_frame_count = 0; static int waiting_to_loading_frame_count_ratio = 0; -// Used when |render_as_new_tab| is true. -static SkBitmap* new_tab_mask = NULL; -static SkBitmap* new_tab_shadow = NULL; - TabRenderer::TabImage TabRenderer::tab_alpha = {0}; TabRenderer::TabImage TabRenderer::tab_active = {0}; -TabRenderer::TabImage TabRenderer::tab_active_nano = {0}; TabRenderer::TabImage TabRenderer::tab_inactive = {0}; -TabRenderer::TabImage TabRenderer::tab_alpha_nano = {0}; // Max opacity for the mini-tab title change animation. const double kMiniTitleChangeThrobOpacity = 0.75; @@ -212,7 +205,7 @@ class TabCloseButton : public views::ImageButton { } private: - DISALLOW_COPY_AND_ASSIGN(TabCloseButton); + DISALLOW_EVIL_CONSTRUCTORS(TabCloseButton); }; } // namespace @@ -253,7 +246,7 @@ class TabRenderer::FavIconCrashAnimation : public Animation, private: TabRenderer* target_; - DISALLOW_COPY_AND_ASSIGN(FavIconCrashAnimation); + DISALLOW_EVIL_CONSTRUCTORS(FavIconCrashAnimation); }; //////////////////////////////////////////////////////////////////////////////// @@ -289,10 +282,6 @@ TabRenderer::~TabRenderer() { delete crash_animation_; } -void TabRenderer::SizeToNewTabButtonImages() { - SetBounds(x(), y(), new_tab_shadow->width(), new_tab_shadow->height()); -} - void TabRenderer::ViewHierarchyChanged(bool is_add, View* parent, View* child) { if (parent->GetThemeProvider()) SetThemeProvider(parent->GetThemeProvider()); @@ -418,11 +407,6 @@ void TabRenderer::StopMiniTabTitleAnimation() { mini_title_animation_->Stop(); } -void TabRenderer::SetAnimationContainer(AnimationContainer* container) { - container_ = container; - pulse_animation_->SetContainer(container); -} - void TabRenderer::PaintIcon(gfx::Canvas* canvas) { if (animation_state_ != ANIMATION_NONE) { PaintLoadingAnimation(canvas); @@ -518,15 +502,6 @@ void TabRenderer::OnMouseExited(const views::MouseEvent& e) { // TabRenderer, views::View overrides: void TabRenderer::Paint(gfx::Canvas* canvas) { - if (data_.render_as_new_tab) { - if (UILayoutIsRightToLeft()) { - canvas->TranslateInt(width(), 0); - canvas->ScaleInt(-1, 1); - } - PaintAsNewTab(canvas); - return; - } - // Don't paint if we're narrower than we can render correctly. (This should // only happen during animations). if (width() < GetMinimumUnselectedSize().width() && !mini()) @@ -740,47 +715,45 @@ void TabRenderer::PaintInactiveTabBackground(gfx::Canvas* canvas) { int bg_offset_y = GetThemeProvider()->HasCustomImage(tab_id) ? 0 : background_offset_.y(); - if (!data_.app) { - // Draw left edge. Don't draw over the toolbar, as we're not the foreground - // tab. - SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap( - *tab_bg, offset, bg_offset_y, tab_active.l_width, height()); - SkBitmap theme_l = - SkBitmapOperations::CreateMaskedBitmap(tab_l, *tab_alpha.image_l); - canvas->DrawBitmapInt(theme_l, - 0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap, - 0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap, - false); - - // Draw right edge. Again, don't draw over the toolbar. - SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg, - offset + width() - tab_active.r_width, bg_offset_y, - tab_active.r_width, height()); - SkBitmap theme_r = - SkBitmapOperations::CreateMaskedBitmap(tab_r, *tab_alpha.image_r); - canvas->DrawBitmapInt(theme_r, - 0, 0, theme_r.width(), theme_r.height() - kToolbarOverlap, - width() - theme_r.width(), 0, theme_r.width(), - theme_r.height() - kToolbarOverlap, false); - - // Draw center. Instead of masking out the top portion we simply skip over - // it by incrementing by kDropShadowHeight, since it's a simple rectangle. - // And again, don't draw over the toolbar. - canvas->TileImageInt(*tab_bg, - offset + tab_active.l_width, bg_offset_y + kDropShadowHeight, - tab_active.l_width, kDropShadowHeight, - width() - tab_active.l_width - tab_active.r_width, - height() - kDropShadowHeight - kToolbarOverlap); - - // Now draw the highlights/shadows around the tab edge. - canvas->DrawBitmapInt(*tab_inactive.image_l, 0, 0); - canvas->TileImageInt(*tab_inactive.image_c, - tab_inactive.l_width, 0, - width() - tab_inactive.l_width - tab_inactive.r_width, - height()); - canvas->DrawBitmapInt(*tab_inactive.image_r, - width() - tab_inactive.r_width, 0); - } + // Draw left edge. Don't draw over the toolbar, as we're not the foreground + // tab. + SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap( + *tab_bg, offset, bg_offset_y, tab_active.l_width, height()); + SkBitmap theme_l = + SkBitmapOperations::CreateMaskedBitmap(tab_l, *tab_alpha.image_l); + canvas->DrawBitmapInt(theme_l, + 0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap, + 0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap, + false); + + // Draw right edge. Again, don't draw over the toolbar. + SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg, + offset + width() - tab_active.r_width, bg_offset_y, + tab_active.r_width, height()); + SkBitmap theme_r = + SkBitmapOperations::CreateMaskedBitmap(tab_r, *tab_alpha.image_r); + canvas->DrawBitmapInt(theme_r, + 0, 0, theme_r.width(), theme_r.height() - kToolbarOverlap, + width() - theme_r.width(), 0, theme_r.width(), + theme_r.height() - kToolbarOverlap, false); + + // Draw center. Instead of masking out the top portion we simply skip over it + // by incrementing by kDropShadowHeight, since it's a simple rectangle. And + // again, don't draw over the toolbar. + canvas->TileImageInt(*tab_bg, + offset + tab_active.l_width, bg_offset_y + kDropShadowHeight, + tab_active.l_width, kDropShadowHeight, + width() - tab_active.l_width - tab_active.r_width, + height() - kDropShadowHeight - kToolbarOverlap); + + // Now draw the highlights/shadows around the tab edge. + canvas->DrawBitmapInt(*tab_inactive.image_l, 0, 0); + canvas->TileImageInt(*tab_inactive.image_c, + tab_inactive.l_width, 0, + width() - tab_inactive.l_width - tab_inactive.r_width, + height()); + canvas->DrawBitmapInt(*tab_inactive.image_r, + width() - tab_inactive.r_width, 0); } void TabRenderer::PaintActiveTabBackground(gfx::Canvas* canvas) { @@ -792,39 +765,33 @@ void TabRenderer::PaintActiveTabBackground(gfx::Canvas* canvas) { SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(IDR_THEME_TOOLBAR); - // App tabs are drawn slightly differently (as nano tabs). - TabImage* tab_image = data_.app ? &tab_active_nano : &tab_active; - TabImage* alpha = data_.app ? &tab_alpha_nano : &tab_alpha; - // Draw left edge. SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap( - *tab_bg, offset, 0, tab_image->l_width, height()); + *tab_bg, offset, 0, tab_active.l_width, height()); SkBitmap theme_l = - SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l); + SkBitmapOperations::CreateMaskedBitmap(tab_l, *tab_alpha.image_l); canvas->DrawBitmapInt(theme_l, 0, 0); // Draw right edge. SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg, - offset + width() - tab_image->r_width, 0, tab_image->r_width, height()); + offset + width() - tab_active.r_width, 0, tab_active.r_width, height()); SkBitmap theme_r = - SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r); - canvas->DrawBitmapInt(theme_r, width() - tab_image->r_width, 0); + SkBitmapOperations::CreateMaskedBitmap(tab_r, *tab_alpha.image_r); + canvas->DrawBitmapInt(theme_r, width() - tab_active.r_width, 0); // Draw center. Instead of masking out the top portion we simply skip over it // by incrementing by kDropShadowHeight, since it's a simple rectangle. canvas->TileImageInt(*tab_bg, - offset + tab_image->l_width, - kDropShadowHeight + tab_image->y_offset, - tab_image->l_width, - kDropShadowHeight + tab_image->y_offset, - width() - tab_image->l_width - tab_image->r_width, - height() - kDropShadowHeight - tab_image->y_offset); + offset + tab_active.l_width, kDropShadowHeight, + tab_active.l_width, kDropShadowHeight, + width() - tab_active.l_width - tab_active.r_width, + height() - kDropShadowHeight); // Now draw the highlights/shadows around the tab edge. - canvas->DrawBitmapInt(*tab_image->image_l, 0, 0); - canvas->TileImageInt(*tab_image->image_c, tab_image->l_width, 0, - width() - tab_image->l_width - tab_image->r_width, height()); - canvas->DrawBitmapInt(*tab_image->image_r, width() - tab_image->r_width, 0); + canvas->DrawBitmapInt(*tab_active.image_l, 0, 0); + canvas->TileImageInt(*tab_active.image_c, tab_active.l_width, 0, + width() - tab_active.l_width - tab_active.r_width, height()); + canvas->DrawBitmapInt(*tab_active.image_r, width() - tab_active.r_width, 0); } void TabRenderer::PaintLoadingAnimation(gfx::Canvas* canvas) { @@ -852,47 +819,6 @@ void TabRenderer::PaintLoadingAnimation(gfx::Canvas* canvas) { false); } -void TabRenderer::PaintAsNewTab(gfx::Canvas* canvas) { - bool is_otr = data_.off_the_record; - - // The tab image needs to be lined up with the background image - // so that it feels partially transparent. These offsets represent the tab - // position within the frame background image. - int offset = GetX(views::View::APPLY_MIRRORING_TRANSFORMATION) + - background_offset_.x(); - - int tab_id; - if (GetWidget() && - GetWidget()->GetWindow()->GetNonClientView()->UseNativeFrame()) { - tab_id = IDR_THEME_TAB_BACKGROUND_V; - } else { - tab_id = is_otr ? IDR_THEME_TAB_BACKGROUND_INCOGNITO : - IDR_THEME_TAB_BACKGROUND; - } - - SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(tab_id); - - // If the theme is providing a custom background image, then its top edge - // should be at the top of the tab. Otherwise, we assume that the background - // image is a composited foreground + frame image. - int bg_offset_y = GetThemeProvider()->HasCustomImage(tab_id) ? - 0 : background_offset_.y(); - - SkBitmap image = SkBitmapOperations::CreateTiledBitmap( - *tab_bg, offset, bg_offset_y, new_tab_mask->width(), - new_tab_mask->height()); - image = SkBitmapOperations::CreateMaskedBitmap(image, *new_tab_mask); - canvas->DrawBitmapInt(image, - 0, 0, image.width(), image.height(), - 0, 0, image.width(), image.height(), - false); - - canvas->DrawBitmapInt(*new_tab_shadow, - 0, 0, new_tab_shadow->width(), new_tab_shadow->height(), - 0, 0, new_tab_shadow->width(), new_tab_shadow->height(), - false); -} - int TabRenderer::IconCapacity() const { if (height() < GetMinimumUnselectedSize().height()) return 0; @@ -918,9 +844,6 @@ bool TabRenderer::ShouldShowCloseBox() const { } double TabRenderer::GetThrobValue() { - if (data_.alpha != 1) - return data_.alpha; - if (pulse_animation_->IsAnimating()) return pulse_animation_->GetCurrentValue() * kHoverOpacity; @@ -969,38 +892,21 @@ void TabRenderer::LoadTabImages() { tab_alpha.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_LEFT); tab_alpha.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_RIGHT); - tab_alpha_nano.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_NANO_LEFT); - tab_alpha_nano.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_NANO_RIGHT); - tab_active.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT); tab_active.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER); tab_active.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT); tab_active.l_width = tab_active.image_l->width(); tab_active.r_width = tab_active.image_r->width(); - // This is high much taller *visually* the regular tab is compared to the - // nano tabs. The images are the same height, this is really just the - // difference in whitespace above the tab image. - const int kMiniTabDiffHeight = 14; - - tab_active_nano.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_NANO_LEFT); - tab_active_nano.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_NANO_CENTER); - tab_active_nano.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_NANO_RIGHT); - tab_active_nano.l_width = tab_active_nano.image_l->width(); - tab_active_nano.r_width = tab_active_nano.image_r->width(); - tab_active_nano.y_offset = kMiniTabDiffHeight; - tab_inactive.image_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT); tab_inactive.image_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER); tab_inactive.image_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT); + tab_inactive.l_width = tab_inactive.image_l->width(); tab_inactive.r_width = tab_inactive.image_r->width(); loading_animation_frames = rb.GetBitmapNamed(IDR_THROBBER); waiting_animation_frames = rb.GetBitmapNamed(IDR_THROBBER_WAITING); - - new_tab_mask = rb.GetBitmapNamed(IDR_TAB_ALPHA_NEW_TAB); - new_tab_shadow = rb.GetBitmapNamed(IDR_TAB_NEW_TAB_SHADOW); } void TabRenderer::SetBlocked(bool blocked) { diff --git a/chrome/browser/views/tabs/tab_renderer.h b/chrome/browser/views/tabs/tab_renderer.h index fc01a7a..2e309c6 100644 --- a/chrome/browser/views/tabs/tab_renderer.h +++ b/chrome/browser/views/tabs/tab_renderer.h @@ -1,19 +1,17 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_H_ -#define CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_H_ +#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_H__ +#define CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_H__ #include "app/animation.h" -#include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/string16.h" #include "gfx/point.h" #include "views/controls/button/image_button.h" #include "views/view.h" -class AnimationContainer; class SlideAnimation; class TabContents; class ThrobAnimation; @@ -39,11 +37,6 @@ class TabRenderer : public views::View, TabRenderer(); virtual ~TabRenderer(); - // Sizes the renderer to the size of the new tab images. This is used - // during the new tab animation. See TabStrip's description of AnimationType - // for details. - void SizeToNewTabButtonImages(); - // Overridden from views: void ViewHierarchyChanged(bool is_add, View* parent, View* child); ThemeProvider* GetThemeProvider(); @@ -62,26 +55,10 @@ class TabRenderer : public views::View, void set_mini(bool mini) { data_.mini = mini; } bool mini() const { return data_.mini; } - // Sets the mini-state of the tab. - void set_app(bool app) { data_.app = app; } - bool app() const { return data_.app; } - // Sets the phantom state of the tab. void set_phantom(bool phantom) { data_.phantom = phantom; } bool phantom() const { return data_.phantom; } - // Used during new tab animation to force the tab to render a new tab like - // animation. - void set_render_as_new_tab(bool value) { data_.render_as_new_tab = value; } - - // Sets the alpha value to render the tab at. This is used during the new - // tab animation. - void set_alpha(double value) { data_.alpha = value; } - - // Forces the tab to render unselected even though it is selected. - void set_render_unselected(bool value) { data_.render_unselected = value; } - bool render_unselected() const { return data_.render_unselected; } - // Are we in the process of animating a mini tab state change on this tab? void set_animating_mini_change(bool value); @@ -116,9 +93,6 @@ class TabRenderer : public views::View, theme_provider_ = provider; } - // Sets the container all animations run from. - void SetAnimationContainer(AnimationContainer* container); - // Paints the icon. Most of the time you'll want to invoke Paint directly, but // in certain situations this invoked outside of Paint. void PaintIcon(gfx::Canvas* canvas); @@ -184,7 +158,6 @@ class TabRenderer : public views::View, void PaintInactiveTabBackground(gfx::Canvas* canvas); void PaintActiveTabBackground(gfx::Canvas* canvas); void PaintLoadingAnimation(gfx::Canvas* canvas); - void PaintAsNewTab(gfx::Canvas* canvas); // Returns the number of favicon-size elements that can fit in the tab's // current size. @@ -238,11 +211,7 @@ class TabRenderer : public views::View, mini(false), blocked(false), animating_mini_change(false), - phantom(false), - app(false), - render_as_new_tab(false), - render_unselected(false), - alpha(1) { + phantom(false) { } SkBitmap favicon; @@ -255,10 +224,6 @@ class TabRenderer : public views::View, bool blocked; bool animating_mini_change; bool phantom; - bool app; - bool render_as_new_tab; - bool render_unselected; - double alpha; }; TabData data_; @@ -268,13 +233,10 @@ class TabRenderer : public views::View, SkBitmap* image_r; int l_width; int r_width; - int y_offset; }; static TabImage tab_active; - static TabImage tab_active_nano; static TabImage tab_inactive; static TabImage tab_alpha; - static TabImage tab_alpha_nano; // Whether we're showing the icon. It is cached so that we can detect when it // changes and layout appropriately. @@ -298,12 +260,10 @@ class TabRenderer : public views::View, ThemeProvider* theme_provider_; - scoped_refptr container_; - static void InitClass(); static bool initialized_; - DISALLOW_COPY_AND_ASSIGN(TabRenderer); + DISALLOW_EVIL_CONSTRUCTORS(TabRenderer); }; -#endif // CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_H_ +#endif // CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_H__ diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc index a28ff52b..1a9edb3 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -4,14 +4,12 @@ #include "chrome/browser/views/tabs/tab_strip.h" -#include "app/animation_container.h" #include "app/drag_drop_types.h" #include "app/l10n_util.h" #include "app/os_exchange_data.h" #include "app/resource_bundle.h" #include "app/slide_animation.h" #include "base/command_line.h" -#include "base/compiler_specific.h" #include "base/stl_util-inl.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_theme_provider.h" @@ -27,7 +25,6 @@ #include "chrome/browser/views/tabs/tab.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" -#include "chrome/common/url_constants.h" #include "gfx/canvas.h" #include "gfx/path.h" #include "gfx/size.h" @@ -57,21 +54,10 @@ using views::DropTargetEvent; -// Duration of the first step in a new tab animation. -static const int kNewTabDurationMs = 50; - -// Duration of the last step in the new tab animation. -static const int kNewTab3DurationMs = 100; - -// Amount in pixels newly inserted tabs go past target bounds before animating -// to final position. This is used for ANIMATION_NEW_TAB_2. -static const int kNewTabOvershoot = 9; - -// Amount in pixels the newly inserted tab is clipped against the previous -// tab while animating. This is used to make sure the user doesn't see the -// newly inserted tab behind other tabs and so that its shadow isn't visible -// until the user can actually see the tab. -static const int kNetTabSelectedOffset = -13; +static const int kDefaultAnimationDurationMs = 200; +static const int kResizeLayoutAnimationDurationMs = 200; +static const int kReorderAnimationDurationMs = 200; +static const int kMiniTabAnimationDurationMs = 200; static const int kNewTabButtonHOffset = -5; static const int kNewTabButtonVOffset = 5; @@ -95,27 +81,6 @@ static inline int Round(double x) { return static_cast(floor(x + 0.5)); } -namespace { - -// Animation delegate used during new tab animation step 2 to vary the alpha of -// the tab. -class NewTabAlphaDelegate - : public views::BoundsAnimator::OwnedAnimationDelegate { - public: - explicit NewTabAlphaDelegate(Tab* tab) : tab_(tab) { - } - - virtual void AnimationProgressed(const Animation* animation) { - if (tab_->render_unselected()) - tab_->set_alpha(animation->GetCurrentValue()); - } - - private: - Tab* tab_; - - DISALLOW_COPY_AND_ASSIGN(NewTabAlphaDelegate); -}; - /////////////////////////////////////////////////////////////////////////////// // NewTabButton // @@ -159,44 +124,292 @@ class NewTabButton : public views::ImageButton { DISALLOW_COPY_AND_ASSIGN(NewTabButton); }; -} // namespace - -// AnimationDelegate used when removing a tab. Does the necessary cleanup when -// done. -class TabStrip::RemoveTabDelegate - : public views::BoundsAnimator::OwnedAnimationDelegate { +/////////////////////////////////////////////////////////////////////////////// +// +// TabAnimation +// +// A base class for all TabStrip animations. +// +class TabStrip::TabAnimation : public AnimationDelegate { public: - RemoveTabDelegate(TabStrip* tab_strip, Tab* tab) - : tabstrip_(tab_strip), - tab_(tab) { + friend class TabStrip; + + // Possible types of animation. + enum Type { + INSERT, + REMOVE, + MOVE, + RESIZE, + MINI, + MINI_MOVE + }; + + TabAnimation(TabStrip* tabstrip, Type type) + : tabstrip_(tabstrip), + animation_(this), + start_selected_width_(0), + start_unselected_width_(0), + end_selected_width_(0), + end_unselected_width_(0), + layout_on_completion_(false), + type_(type) { + } + virtual ~TabAnimation() {} + + Type type() const { return type_; } + + void Start() { + animation_.SetSlideDuration(GetDuration()); + animation_.SetTweenType(SlideAnimation::EASE_OUT); + if (!animation_.IsShowing()) { + animation_.Reset(); + animation_.Show(); + } + } + + void Stop() { + animation_.Stop(); + } + + void set_layout_on_completion(bool layout_on_completion) { + layout_on_completion_ = layout_on_completion; + } + + // Retrieves the width for the Tab at the specified index if an animation is + // active. + static double GetCurrentTabWidth(TabStrip* tabstrip, + TabStrip::TabAnimation* animation, + int index) { + Tab* tab = tabstrip->GetTabAt(index); + double tab_width; + if (tab->mini()) { + tab_width = Tab::GetMiniWidth(); + } else { + double unselected, selected; + tabstrip->GetCurrentTabWidths(&unselected, &selected); + tab_width = tab->IsSelected() ? selected : unselected; + } + if (animation) { + double specified_tab_width = animation->GetWidthForTab(index); + if (specified_tab_width != -1) + tab_width = specified_tab_width; + } + return tab_width; + } + + // Overridden from AnimationDelegate: + virtual void AnimationProgressed(const Animation* animation) { + tabstrip_->AnimationLayout(end_unselected_width_); } virtual void AnimationEnded(const Animation* animation) { - CompleteRemove(); + tabstrip_->FinishAnimation(this, layout_on_completion_); + // This object is destroyed now, so we can't do anything else after this. } virtual void AnimationCanceled(const Animation* animation) { - // We can be canceled for two interesting reasons: - // . The tab we reference was dragged back into the tab strip. In this case - // we don't want to remove the tab (closing is false). - // . The drag was completed before the animation completed - // (DestroyDraggedSourceTab). In this case we need to remove the tab - // (closing is true). - if (tab_->closing()) - CompleteRemove(); + AnimationEnded(animation); + } + + // Returns the gap before the tab at the specified index. Subclass if during + // an animation you need to insert a gap before a tab. + virtual double GetGapWidth(int index) { + return 0; + } + + protected: + // Returns the duration of the animation. + virtual int GetDuration() const { + return kDefaultAnimationDurationMs; + } + + // Subclasses override to return the width of the Tab at the specified index + // at the current animation frame. -1 indicates the default width should be + // used for the Tab. + virtual double GetWidthForTab(int index) const { + return -1; // Use default. + } + + // Figure out the desired start and end widths for the specified pre- and + // post- animation tab counts. + void GenerateStartAndEndWidths(int start_tab_count, int end_tab_count, + int start_mini_count, + int end_mini_count) { + tabstrip_->GetDesiredTabWidths(start_tab_count, start_mini_count, + &start_unselected_width_, + &start_selected_width_); + double standard_tab_width = + static_cast(TabRenderer::GetStandardSize().width()); + if (start_tab_count < end_tab_count && + start_unselected_width_ < standard_tab_width) { + double minimum_tab_width = + static_cast(TabRenderer::GetMinimumUnselectedSize().width()); + start_unselected_width_ -= minimum_tab_width / start_tab_count; + } + tabstrip_->GenerateIdealBounds(); + tabstrip_->GetDesiredTabWidths(end_tab_count, end_mini_count, + &end_unselected_width_, + &end_selected_width_); } + TabStrip* tabstrip_; + SlideAnimation animation_; + + double start_selected_width_; + double start_unselected_width_; + double end_selected_width_; + double end_unselected_width_; + private: - void CompleteRemove() { - if (!tab_->closing()) { - // The tab was added back yet we weren't canceled. This shouldn't happen. - NOTREACHED(); - return; + // True if a complete re-layout is required upon completion of the animation. + // Subclasses set this if they don't perform a complete layout + // themselves and canceling the animation may leave the strip in an + // inconsistent state. + bool layout_on_completion_; + + const Type type_; + + DISALLOW_COPY_AND_ASSIGN(TabAnimation); +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Handles insertion of a Tab at |index|. +class TabStrip::InsertTabAnimation : public TabStrip::TabAnimation { + public: + explicit InsertTabAnimation(TabStrip* tabstrip, int index) + : TabAnimation(tabstrip, INSERT), + index_(index) { + int tab_count = tabstrip->GetTabCount(); + int end_mini_count = tabstrip->GetMiniTabCount(); + int start_mini_count = end_mini_count; + if (index < end_mini_count) + start_mini_count--; + GenerateStartAndEndWidths(tab_count - 1, tab_count, start_mini_count, + end_mini_count); + } + virtual ~InsertTabAnimation() {} + + protected: + // Overridden from TabStrip::TabAnimation: + virtual double GetWidthForTab(int index) const { + if (index == index_) { + bool is_selected = tabstrip_->model()->selected_index() == index; + double start_width, target_width; + if (index < tabstrip_->GetMiniTabCount()) { + start_width = Tab::GetMinimumSelectedSize().width(); + target_width = Tab::GetMiniWidth(); + } else { + target_width = + is_selected ? end_unselected_width_ : end_selected_width_; + start_width = + is_selected ? Tab::GetMinimumSelectedSize().width() : + Tab::GetMinimumUnselectedSize().width(); + } + double delta = target_width - start_width; + if (delta > 0) + return start_width + (delta * animation_.GetCurrentValue()); + return start_width; + } + + if (tabstrip_->GetTabAt(index)->mini()) + return Tab::GetMiniWidth(); + + if (tabstrip_->GetTabAt(index)->IsSelected()) { + double delta = end_selected_width_ - start_selected_width_; + return start_selected_width_ + (delta * animation_.GetCurrentValue()); + } + + double delta = end_unselected_width_ - start_unselected_width_; + return start_unselected_width_ + (delta * animation_.GetCurrentValue()); + } + + private: + int index_; + + DISALLOW_COPY_AND_ASSIGN(InsertTabAnimation); +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Handles removal of a Tab from |index| +class TabStrip::RemoveTabAnimation : public TabStrip::TabAnimation { + public: + RemoveTabAnimation(TabStrip* tabstrip, int index, TabContents* contents) + : TabAnimation(tabstrip, REMOVE), + index_(index) { + int tab_count = tabstrip->GetTabCount(); + int start_mini_count = tabstrip->GetMiniTabCount(); + int end_mini_count = start_mini_count; + if (index < start_mini_count) + end_mini_count--; + GenerateStartAndEndWidths(tab_count, tab_count - 1, start_mini_count, + end_mini_count); + // If the last non-mini-tab is being removed we force a layout on + // completion. This is necessary as the value returned by GetTabHOffset + // changes once the tab is actually removed (which happens at the end of + // the animation), and unless we layout GetTabHOffset won't be called after + // the removal. + // We do the same when the last mini-tab is being removed for the same + // reason. + set_layout_on_completion(start_mini_count > 0 && + (end_mini_count == 0 || + (start_mini_count == end_mini_count && + tab_count == start_mini_count + 1))); + } + + // Returns the index of the tab being removed. + int index() const { return index_; } + + virtual ~RemoveTabAnimation() { + } + + protected: + // Overridden from TabStrip::TabAnimation: + virtual double GetWidthForTab(int index) const { + Tab* tab = tabstrip_->GetTabAt(index); + if (index == index_) { + // The tab(s) being removed are gradually shrunken depending on the state + // of the animation. + // Removed animated Tabs are never selected. + if (tab->mini()) { + return animation_.CurrentValueBetween(Tab::GetMiniWidth(), + -kTabHOffset); + } + + double start_width = start_unselected_width_; + // Make sure target_width is at least abs(kTabHOffset), otherwise if + // less than kTabHOffset during layout tabs get negatively offset. + double target_width = + std::max(abs(kTabHOffset), + Tab::GetMinimumUnselectedSize().width() + kTabHOffset); + return animation_.CurrentValueBetween(start_width, target_width); + } + + if (tab->mini()) + return Tab::GetMiniWidth(); + + if (tabstrip_->available_width_for_tabs_ != -1 && + index_ != tabstrip_->GetTabCount() - 1) { + return TabStrip::TabAnimation::GetWidthForTab(index); + } + // All other tabs are sized according to the start/end widths specified at + // the start of the animation. + if (tab->IsSelected()) { + double delta = end_selected_width_ - start_selected_width_; + return start_selected_width_ + (delta * animation_.GetCurrentValue()); } - tabstrip_->RemoveTab(tab_); + double delta = end_unselected_width_ - start_unselected_width_; + return start_unselected_width_ + (delta * animation_.GetCurrentValue()); + } + + virtual void AnimationEnded(const Animation* animation) { + tabstrip_->RemoveTabAt(index_); HighlightCloseButton(); + TabStrip::TabAnimation::AnimationEnded(animation); } + private: // When the animation completes, we send the Container a message to simulate // a mouse moved event at the current mouse position. This tickles the Tab // the mouse is currently over to show the "hot" state of the close button. @@ -226,10 +439,293 @@ class TabStrip::RemoveTabDelegate #endif } - TabStrip* tabstrip_; + int index_; + + DISALLOW_COPY_AND_ASSIGN(RemoveTabAnimation); +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Handles the movement of a Tab from one position to another. +class TabStrip::MoveTabAnimation : public TabStrip::TabAnimation { + public: + MoveTabAnimation(TabStrip* tabstrip, int tab_a_index, int tab_b_index) + : TabAnimation(tabstrip, MOVE), + start_tab_a_bounds_(tabstrip_->GetIdealBounds(tab_b_index)), + start_tab_b_bounds_(tabstrip_->GetIdealBounds(tab_a_index)) { + tab_a_ = tabstrip_->GetTabAt(tab_a_index); + tab_b_ = tabstrip_->GetTabAt(tab_b_index); + + // Since we don't do a full TabStrip re-layout, we need to force a full + // layout upon completion since we're not guaranteed to be in a good state + // if for example the animation is canceled. + set_layout_on_completion(true); + } + virtual ~MoveTabAnimation() {} + + // Overridden from AnimationDelegate: + virtual void AnimationProgressed(const Animation* animation) { + // Position Tab A + double distance = start_tab_b_bounds_.x() - start_tab_a_bounds_.x(); + double delta = distance * animation_.GetCurrentValue(); + double new_x = start_tab_a_bounds_.x() + delta; + tab_a_->SetBounds(Round(new_x), tab_a_->y(), tab_a_->width(), + tab_a_->height()); + + // Position Tab B + distance = start_tab_a_bounds_.x() - start_tab_b_bounds_.x(); + delta = distance * animation_.GetCurrentValue(); + new_x = start_tab_b_bounds_.x() + delta; + tab_b_->SetBounds(Round(new_x), tab_b_->y(), tab_b_->width(), + tab_b_->height()); + + tabstrip_->SchedulePaint(); + } + + protected: + // Overridden from TabStrip::TabAnimation: + virtual int GetDuration() const { return kReorderAnimationDurationMs; } + + private: + // The two tabs being exchanged. + Tab* tab_a_; + Tab* tab_b_; + + // ...and their bounds. + gfx::Rect start_tab_a_bounds_; + gfx::Rect start_tab_b_bounds_; + + DISALLOW_COPY_AND_ASSIGN(MoveTabAnimation); +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Handles the animated resize layout of the entire TabStrip from one width +// to another. +class TabStrip::ResizeLayoutAnimation : public TabStrip::TabAnimation { + public: + explicit ResizeLayoutAnimation(TabStrip* tabstrip) + : TabAnimation(tabstrip, RESIZE) { + int tab_count = tabstrip->GetTabCount(); + int mini_tab_count = tabstrip->GetMiniTabCount(); + GenerateStartAndEndWidths(tab_count, tab_count, mini_tab_count, + mini_tab_count); + InitStartState(); + } + virtual ~ResizeLayoutAnimation() { + } + + // Overridden from AnimationDelegate: + virtual void AnimationEnded(const Animation* animation) { + tabstrip_->needs_resize_layout_ = false; + TabStrip::TabAnimation::AnimationEnded(animation); + } + + protected: + // Overridden from TabStrip::TabAnimation: + virtual int GetDuration() const { + return kResizeLayoutAnimationDurationMs; + } + + virtual double GetWidthForTab(int index) const { + Tab* tab = tabstrip_->GetTabAt(index); + if (tab->mini()) + return Tab::GetMiniWidth(); + + if (tab->IsSelected()) { + return animation_.CurrentValueBetween(start_selected_width_, + end_selected_width_); + } + + return animation_.CurrentValueBetween(start_unselected_width_, + end_unselected_width_); + } + + private: + // We need to start from the current widths of the Tabs as they were last + // laid out, _not_ the last known good state, which is what'll be done if we + // don't measure the Tab sizes here and just go with the default TabAnimation + // behavior... + void InitStartState() { + for (int i = 0; i < tabstrip_->GetTabCount(); ++i) { + Tab* current_tab = tabstrip_->GetTabAt(i); + if (!current_tab->mini()) { + if (current_tab->IsSelected()) { + start_selected_width_ = current_tab->width(); + } else { + start_unselected_width_ = current_tab->width(); + } + } + } + } + + DISALLOW_COPY_AND_ASSIGN(ResizeLayoutAnimation); +}; + +// Handles a tabs mini-state changing while the tab does not change position +// in the model. +class TabStrip::MiniTabAnimation : public TabStrip::TabAnimation { + public: + explicit MiniTabAnimation(TabStrip* tabstrip, int index) + : TabAnimation(tabstrip, MINI), + index_(index) { + int tab_count = tabstrip->GetTabCount(); + int start_mini_count = tabstrip->GetMiniTabCount(); + int end_mini_count = start_mini_count; + if (tabstrip->GetTabAt(index)->mini()) + start_mini_count--; + else + start_mini_count++; + tabstrip_->GetTabAt(index)->set_animating_mini_change(true); + GenerateStartAndEndWidths(tab_count, tab_count, start_mini_count, + end_mini_count); + } + + protected: + // Overridden from TabStrip::TabAnimation: + virtual int GetDuration() const { + return kMiniTabAnimationDurationMs; + } + + virtual double GetWidthForTab(int index) const { + Tab* tab = tabstrip_->GetTabAt(index); + + if (index == index_) { + if (tab->mini()) { + return animation_.CurrentValueBetween( + start_selected_width_, + static_cast(Tab::GetMiniWidth())); + } else { + return animation_.CurrentValueBetween( + static_cast(Tab::GetMiniWidth()), + end_selected_width_); + } + } else if (tab->mini()) { + return Tab::GetMiniWidth(); + } + + if (tab->IsSelected()) { + return animation_.CurrentValueBetween(start_selected_width_, + end_selected_width_); + } + + return animation_.CurrentValueBetween(start_unselected_width_, + end_unselected_width_); + } + + private: + // Index of the tab whose mini state changed. + int index_; + + DISALLOW_COPY_AND_ASSIGN(MiniTabAnimation); +}; + +//////////////////////////////////////////////////////////////////////////////// + +// Handles the animation when a tabs mini state changes and the tab moves as a +// result. +class TabStrip::MiniMoveAnimation : public TabStrip::TabAnimation { + public: + explicit MiniMoveAnimation(TabStrip* tabstrip, + int from_index, + int to_index, + const gfx::Rect& start_bounds) + : TabAnimation(tabstrip, MINI_MOVE), + tab_(tabstrip->GetTabAt(to_index)), + start_bounds_(start_bounds), + from_index_(from_index), + to_index_(to_index) { + int tab_count = tabstrip->GetTabCount(); + int start_mini_count = tabstrip->GetMiniTabCount(); + int end_mini_count = start_mini_count; + if (tabstrip->GetTabAt(to_index)->mini()) + start_mini_count--; + else + start_mini_count++; + GenerateStartAndEndWidths(tab_count, tab_count, start_mini_count, + end_mini_count); + target_bounds_ = tabstrip->GetIdealBounds(to_index); + tab_->set_animating_mini_change(true); + } + + // Overridden from AnimationDelegate: + virtual void AnimationProgressed(const Animation* animation) { + // Do the normal layout. + TabAnimation::AnimationProgressed(animation); + + // Then special case the position of the tab being moved. + int x = animation_.CurrentValueBetween(start_bounds_.x(), + target_bounds_.x()); + int width = animation_.CurrentValueBetween(start_bounds_.width(), + target_bounds_.width()); + gfx::Rect tab_bounds(x, start_bounds_.y(), width, + start_bounds_.height()); + tab_->SetBounds(tab_bounds); + } + + virtual void AnimationEnded(const Animation* animation) { + tabstrip_->needs_resize_layout_ = false; + TabStrip::TabAnimation::AnimationEnded(animation); + } + + virtual double GetGapWidth(int index) { + if (to_index_ < from_index_) { + // The tab was mini. + if (index == to_index_) { + double current_size = + animation_.CurrentValueBetween(0, target_bounds_.width()); + if (current_size < -kTabHOffset) + return -(current_size + kTabHOffset); + } else if (index == from_index_ + 1) { + return animation_.CurrentValueBetween(start_bounds_.width(), 0); + } + } else { + // The tab was made a normal tab. + if (index == from_index_) { + return animation_.CurrentValueBetween(Tab::GetMiniWidth() + + kTabHOffset, 0); + } + } + return 0; + } + + protected: + // Overridden from TabStrip::TabAnimation: + virtual int GetDuration() const { return kReorderAnimationDurationMs; } + + virtual double GetWidthForTab(int index) const { + Tab* tab = tabstrip_->GetTabAt(index); + + if (index == to_index_) + return animation_.CurrentValueBetween(0, target_bounds_.width()); + + if (tab->mini()) + return Tab::GetMiniWidth(); + + if (tab->IsSelected()) { + return animation_.CurrentValueBetween(start_selected_width_, + end_selected_width_); + } + + return animation_.CurrentValueBetween(start_unselected_width_, + end_unselected_width_); + } + + private: + // The tab being moved. Tab* tab_; - DISALLOW_COPY_AND_ASSIGN(RemoveTabDelegate); + // Initial bounds of tab_. + gfx::Rect start_bounds_; + + // Target bounds. + gfx::Rect target_bounds_; + + // Start and end indices of the tab. + int from_index_; + int to_index_; + + DISALLOW_COPY_AND_ASSIGN(MiniMoveAnimation); }; /////////////////////////////////////////////////////////////////////////////// @@ -245,14 +741,13 @@ TabStrip::TabStrip(TabStripModel* model) needs_resize_layout_(false), current_unselected_width_(Tab::GetStandardSize().width()), current_selected_width_(Tab::GetStandardSize().width()), - available_width_for_tabs_(-1), - animation_container_(new AnimationContainer()), - ALLOW_THIS_IN_INITIALIZER_LIST(bounds_animator_(this)), - animation_type_(ANIMATION_DEFAULT) { + available_width_for_tabs_(-1) { Init(); } TabStrip::~TabStrip() { + active_animation_.reset(NULL); + // TODO(beng): (1031854) Restore this line once XPFrame/VistaFrame are dead. // model_->RemoveObserver(this); @@ -280,34 +775,36 @@ void TabStrip::DestroyDragController() { void TabStrip::DestroyDraggedSourceTab(Tab* tab) { // We could be running an animation that references this Tab. - StopAnimating(true); - + if (active_animation_.get()) + active_animation_->Stop(); // Make sure we leave the tab_data_ vector in a consistent state, otherwise // we'll be pointing to tabs that have been deleted and removed from the // child view list. - int tab_data_index = TabDataIndexOfTab(tab); - if (tab_data_index != -1) { - if (!model_->closing_all()) - NOTREACHED() << "Leaving in an inconsistent state!"; - tab_data_.erase(tab_data_.begin() + tab_data_index); + std::vector::iterator it = tab_data_.begin(); + for (; it != tab_data_.end(); ++it) { + if (it->tab == tab) { + if (!model_->closing_all()) + NOTREACHED() << "Leaving in an inconsistent state!"; + tab_data_.erase(it); + break; + } } - + tab->GetParent()->RemoveChildView(tab); delete tab; - // Force a layout here, because if we've just quickly drag detached a Tab, // the stopping of the active animation above may have left the TabStrip in a // bad (visual) state. Layout(); } -gfx::Rect TabStrip::GetIdealBounds(int tab_data_index) { - DCHECK_GE(tab_data_index, 0); - DCHECK_LT(tab_data_index, GetTabCount()); - return tab_data_[tab_data_index].ideal_bounds; +gfx::Rect TabStrip::GetIdealBounds(int index) { + DCHECK_GE(index, 0); + DCHECK_LT(index, GetTabCount()); + return tab_data_.at(index).ideal_bounds; } Tab* TabStrip::GetSelectedTab() const { - return GetTabAtModelIndex(model()->selected_index()); + return GetTabAtAdjustForAnimation(model()->selected_index()); } void TabStrip::InitTabStripButtons() { @@ -339,7 +836,7 @@ int TabStrip::GetPreferredHeight() { void TabStrip::SetBackgroundOffset(const gfx::Point& offset) { int tab_count = GetTabCount(); for (int i = 0; i < tab_count; ++i) - GetTabAtTabDataIndex(i)->SetBackgroundOffset(offset); + GetTabAt(i)->SetBackgroundOffset(offset); } bool TabStrip::IsPositionInWindowCaption(const gfx::Point& point) { @@ -374,10 +871,12 @@ bool TabStrip::IsDragSessionActive() const { } void TabStrip::UpdateLoadingAnimations() { - for (int i = 0, model_index = 0; i < GetTabCount(); ++i) { - Tab* current_tab = GetTabAtTabDataIndex(i); - if (!current_tab->closing()) { - TabContents* contents = model_->GetTabContentsAt(model_index); + for (int i = 0, index = 0; i < GetTabCount(); ++i, ++index) { + Tab* current_tab = GetTabAt(i); + if (current_tab->closing()) { + --index; + } else { + TabContents* contents = model_->GetTabContentsAt(index); if (!contents || !contents->is_loading()) { current_tab->ValidateLoadingAnimation(Tab::ANIMATION_NONE); } else if (contents->waiting_for_response()) { @@ -385,13 +884,12 @@ void TabStrip::UpdateLoadingAnimations() { } else { current_tab->ValidateLoadingAnimation(Tab::ANIMATION_LOADING); } - model_index++; } } } bool TabStrip::IsAnimating() const { - return bounds_animator_.IsAnimating() || new_tab_timer_.IsRunning(); + return active_animation_.get() != NULL; } TabStrip* TabStrip::AsTabStrip() { @@ -403,7 +901,6 @@ TabStrip* TabStrip::AsTabStrip() { void TabStrip::PaintChildren(gfx::Canvas* canvas) { // Tabs are painted in reverse order, so they stack to the left. - int tab_count = GetTabCount(); // Phantom tabs appear behind all other tabs and are rendered first. To make // them slightly transparent we render them to a different layer. @@ -413,8 +910,8 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) { canvas->saveLayerAlpha(&bounds, kPhantomTabAlpha, SkCanvas::kARGB_ClipLayer_SaveFlag); canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); - for (int i = tab_count - 1; i >= 0; --i) { - Tab* tab = GetTabAtTabDataIndex(i); + for (int i = GetTabCount() - 1; i >= 0; --i) { + Tab* tab = GetTabAt(i); if (tab->phantom()) tab->ProcessPaint(canvas); } @@ -423,8 +920,8 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) { canvas->saveLayerAlpha(&bounds, kPhantomTabIconAlpha, SkCanvas::kARGB_ClipLayer_SaveFlag); canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); - for (int i = tab_count - 1; i >= 0; --i) { - Tab* tab = GetTabAtTabDataIndex(i); + for (int i = GetTabCount() - 1; i >= 0; --i) { + Tab* tab = GetTabAt(i); if (tab->phantom()) { canvas->save(); canvas->ClipRectInt(tab->MirroredX(), tab->y(), tab->width(), @@ -439,27 +936,14 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) { Tab* selected_tab = NULL; - for (int i = tab_count - 1; i >= 0; --i) { - Tab* tab = GetTabAtTabDataIndex(i); + for (int i = GetTabCount() - 1; i >= 0; --i) { + Tab* tab = GetTabAt(i); // We must ask the _Tab's_ model, not ourselves, because in some situations // the model will be different to this object, e.g. when a Tab is being // removed after its TabContents has been destroyed. if (!tab->phantom()) { if (!tab->IsSelected()) { - if (tab->render_unselected() && model_->count() > 1) { - // See comment above kNetTabAnimationSelectedOffset as to why we do - // this. - Tab* last_tab = GetTabAtModelIndex(model_->count() - 2); - canvas->save(); - int clip_x = last_tab->bounds().right() + kNetTabSelectedOffset; - int clip_width = width() - clip_x; - clip_x = MirroredXWithWidthInsideView(clip_x, clip_width); - canvas->ClipRectInt(clip_x, 0, clip_width, height()); - tab->ProcessPaint(canvas); - canvas->restore(); - } else { - tab->ProcessPaint(canvas); - } + tab->ProcessPaint(canvas); } else { selected_tab = tab; } @@ -478,30 +962,23 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) { paint); } - if (animation_type_ == ANIMATION_NEW_TAB_3) - newtab_button_->ProcessPaint(canvas); - // Paint the selected tab last, so it overlaps all the others. if (selected_tab) selected_tab->ProcessPaint(canvas); // Paint the New Tab button. - if (animation_type_ != ANIMATION_NEW_TAB_1 && - animation_type_ != ANIMATION_NEW_TAB_2 && - animation_type_ != ANIMATION_NEW_TAB_3) { - newtab_button_->ProcessPaint(canvas); - } + newtab_button_->ProcessPaint(canvas); } // Overridden to support automation. See automation_proxy_uitest.cc. views::View* TabStrip::GetViewByID(int view_id) const { if (GetTabCount() > 0) { if (view_id == VIEW_ID_TAB_LAST) { - return GetTabAtTabDataIndex(GetTabCount() - 1); + return GetTabAt(GetTabCount() - 1); } else if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) { int index = view_id - VIEW_ID_TAB_0; if (index >= 0 && index < GetTabCount()) { - return GetTabAtTabDataIndex(index); + return GetTabAt(index); } else { return NULL; } @@ -514,15 +991,22 @@ views::View* TabStrip::GetViewByID(int view_id) const { void TabStrip::Layout() { // Called from: // - window resize - StopAnimating(false); - + // - animation completion + if (active_animation_.get()) + active_animation_->Stop(); GenerateIdealBounds(); + int tab_count = GetTabCount(); + int tab_right = 0; - for (int i = 0, tab_count = GetTabCount(); i < tab_count; ++i) - tab_data_[i].tab->SetBounds(tab_data_[i].ideal_bounds); - - newtab_button_->SetBounds(newtab_button_bounds_); - + for (int i = 0; i < tab_count; ++i) { + const gfx::Rect& bounds = tab_data_.at(i).ideal_bounds; + Tab* tab = GetTabAt(i); + tab->set_animating_mini_change(false); + tab->SetBounds(bounds.x(), bounds.y(), bounds.width(), bounds.height()); + tab_right = bounds.right(); + tab_right += GetTabHOffset(i + 1); + } + LayoutNewTabButton(static_cast(tab_right), current_unselected_width_); SchedulePaint(); } @@ -531,9 +1015,6 @@ gfx::Size TabStrip::GetPreferredSize() { } void TabStrip::OnDragEntered(const DropTargetEvent& event) { - // Force animations to stop, otherwise it makes the index calculation tricky. - StopAnimating(true); - UpdateDropIndex(event); } @@ -604,10 +1085,10 @@ views::View* TabStrip::GetViewForPoint(const gfx::Point& point) { // left-adjacent Tab, so we look ahead for it as we walk. int tab_count = GetTabCount(); for (int i = 0; i < tab_count; ++i) { - Tab* next_tab = i < (tab_count - 1) ? GetTabAtTabDataIndex(i + 1) : NULL; + Tab* next_tab = i < (tab_count - 1) ? GetTabAt(i + 1) : NULL; if (next_tab && next_tab->IsSelected() && IsPointInTab(next_tab, point)) return next_tab; - Tab* tab = GetTabAtTabDataIndex(i); + Tab* tab = GetTabAt(i); if (IsPointInTab(tab, point)) return tab; } @@ -636,15 +1117,16 @@ void TabStrip::ViewHierarchyChanged(bool is_add, // TabStrip, TabStripModelObserver implementation: void TabStrip::TabInsertedAt(TabContents* contents, - int model_index, + int index, bool foreground) { DCHECK(contents); - DCHECK(model_index == TabStripModel::kNoTab || - model_->ContainsIndex(model_index)); + DCHECK(index == TabStripModel::kNoTab || model_->ContainsIndex(index)); // This tab may be attached to another browser window, we should notify // renderer. contents->render_view_host()->UpdateBrowserWindowId( contents->controller().window_id().id()); + if (active_animation_.get()) + active_animation_->Stop(); bool contains_tab = false; Tab* tab = NULL; @@ -663,23 +1145,10 @@ void TabStrip::TabInsertedAt(TabContents* contents, } // See if we're already in the list. We don't want to add ourselves twice. - int tab_data_index = TabDataIndexOfTab(tab); - - if (tab_data_index != -1) { - contains_tab = true; - - // Make sure we stop animating the view. This is necessary otherwise when - // the animation is done it'll try to remove the tab. - bounds_animator_.StopAnimatingView(tab); - - // We have the tab, but it might not be at the right index. Reset the data - // to ensure it's at the right index. - TabData tab_data = tab_data_[tab_data_index]; - DCHECK(tab_data.tab == tab); - tab_data_.erase(tab_data_.begin() + tab_data_index); - tab_data_.insert( - tab_data_.begin() + ModelIndexToTabDataIndex(model_index), - tab_data); + std::vector::const_iterator iter = tab_data_.begin(); + for (; iter != tab_data_.end() && !contains_tab; ++iter) { + if (iter->tab == tab) + contains_tab = true; } } @@ -690,43 +1159,40 @@ void TabStrip::TabInsertedAt(TabContents* contents, // Only insert if we're not already in the list. if (!contains_tab) { TabData d = { tab, gfx::Rect() }; - tab_data_.insert(tab_data_.begin() + - ModelIndexToTabDataIndex(model_index), d); - tab->UpdateData(contents, model_->IsPhantomTab(model_index), false); + tab_data_.insert(tab_data_.begin() + index, d); + tab->UpdateData(contents, model_->IsPhantomTab(index), false); } - tab->set_mini(model_->IsMiniTab(model_index)); - tab->set_app(model_->IsAppTab(model_index)); - tab->SetBlocked(model_->IsTabBlocked(model_index)); + tab->set_mini(model_->IsMiniTab(index)); + tab->SetBlocked(model_->IsTabBlocked(index)); // We only add the tab to the child list if it's not already - an invisible // tab maintained by the DraggedTabController will already be parented. - if (!tab->GetParent()) { + if (!tab->GetParent()) AddChildView(tab); - tab->SetAnimationContainer(animation_container_.get()); - } // Don't animate the first tab, it looks weird, and don't animate anything // if the containing window isn't visible yet. if (GetTabCount() > 1 && GetWindow() && GetWindow()->IsVisible()) { - if (!IsDragSessionActive() && - ShouldStartIntertTabAnimationAtEnd(model_index, foreground)) { - StartInsertTabAnimationAtEnd(); - } else { - StartInsertTabAnimation(model_index); - } + StartInsertTabAnimation(index); } else { Layout(); } } -void TabStrip::TabDetachedAt(TabContents* contents, int model_index) { - StartRemoveTabAnimation(model_index); +void TabStrip::TabDetachedAt(TabContents* contents, int index) { + GenerateIdealBounds(); + StartRemoveTabAnimation(index, contents); + // Have to do this _after_ calling StartRemoveTabAnimation, so that any + // previous remove is completed fully and index is valid in sync with the + // model index. + GetTabAt(index)->set_closing(true); } void TabStrip::TabSelectedAt(TabContents* old_contents, TabContents* new_contents, - int model_index, + int index, bool user_gesture) { + DCHECK(index >= 0 && index < GetTabCount()); // We have "tiny tabs" if the tabs are so tiny that the unselected ones are // a different size to the selected ones. bool tiny_tabs = current_unselected_width_ != current_selected_width_; @@ -736,133 +1202,117 @@ void TabStrip::TabSelectedAt(TabContents* old_contents, SchedulePaint(); } - int old_model_index = model_->GetIndexOfTabContents(old_contents); - if (old_model_index >= 0) { - GetTabAtTabDataIndex(ModelIndexToTabDataIndex(old_model_index))-> - StopMiniTabTitleAnimation(); - } + int old_index = model_->GetIndexOfTabContents(old_contents); + if (old_index >= 0) + GetTabAt(old_index)->StopMiniTabTitleAnimation(); } -void TabStrip::TabMoved(TabContents* contents, - int from_model_index, - int to_model_index) { - StartMoveTabAnimation(from_model_index, to_model_index); +void TabStrip::TabMoved(TabContents* contents, int from_index, int to_index) { + gfx::Rect start_bounds = GetIdealBounds(from_index); + Tab* tab = GetTabAt(from_index); + tab_data_.erase(tab_data_.begin() + from_index); + TabData data = {tab, gfx::Rect()}; + tab->set_mini(model_->IsMiniTab(to_index)); + tab->SetBlocked(model_->IsTabBlocked(to_index)); + tab_data_.insert(tab_data_.begin() + to_index, data); + if (tab->phantom() != model_->IsPhantomTab(to_index)) + tab->set_phantom(!tab->phantom()); + GenerateIdealBounds(); + StartMoveTabAnimation(from_index, to_index); } -void TabStrip::TabChangedAt(TabContents* contents, - int model_index, +void TabStrip::TabChangedAt(TabContents* contents, int index, TabChangeType change_type) { // Index is in terms of the model. Need to make sure we adjust that index in // case we have an animation going. - Tab* tab = GetTabAtModelIndex(model_index); + Tab* tab = GetTabAtAdjustForAnimation(index); if (change_type == TITLE_NOT_LOADING) { if (tab->mini() && !tab->IsSelected()) tab->StartMiniTabTitleAnimation(); // We'll receive another notification of the change asynchronously. return; } - tab->UpdateData(contents, model_->IsPhantomTab(model_index), + tab->UpdateData(contents, model_->IsPhantomTab(index), change_type == LOADING_ONLY); tab->UpdateFromModel(); } void TabStrip::TabReplacedAt(TabContents* old_contents, TabContents* new_contents, - int model_index) { - TabChangedAt(new_contents, model_index, ALL); + int index) { + TabChangedAt(new_contents, index, ALL); } -void TabStrip::TabMiniStateChanged(TabContents* contents, int model_index) { - GetTabAtModelIndex(model_index)->set_mini( - model_->IsMiniTab(model_index)); +void TabStrip::TabMiniStateChanged(TabContents* contents, int index) { + GetTabAt(index)->set_mini(model_->IsMiniTab(index)); // Don't animate if the window isn't visible yet. The window won't be visible // when dragging a mini-tab to a new window. if (GetWindow() && GetWindow()->IsVisible()) - StartMiniTabAnimation(); + StartMiniTabAnimation(index); else Layout(); } -void TabStrip::TabBlockedStateChanged(TabContents* contents, int model_index) { - GetTabAtModelIndex(model_index)->SetBlocked( - model_->IsTabBlocked(model_index)); +void TabStrip::TabBlockedStateChanged(TabContents* contents, int index) { + GetTabAt(index)->SetBlocked(model_->IsTabBlocked(index)); } /////////////////////////////////////////////////////////////////////////////// // TabStrip, Tab::Delegate implementation: bool TabStrip::IsTabSelected(const Tab* tab) const { - if (tab->closing() || tab->render_unselected()) + if (tab->closing()) return false; - return GetModelIndexOfTab(tab) == model_->selected_index(); + return GetIndexOfTab(tab) == model_->selected_index(); } bool TabStrip::IsTabPinned(const Tab* tab) const { if (tab->closing()) return false; - return model_->IsTabPinned(GetModelIndexOfTab(tab)); + return model_->IsTabPinned(GetIndexOfTab(tab)); } void TabStrip::SelectTab(Tab* tab) { - int model_index = GetModelIndexOfTab(tab); - if (model_->ContainsIndex(model_index)) - model_->SelectTabContentsAt(model_index, true); + int index = GetIndexOfTab(tab); + if (model_->ContainsIndex(index)) + model_->SelectTabContentsAt(index, true); } void TabStrip::CloseTab(Tab* tab) { - int model_index = GetModelIndexOfTab(tab); - if (model_->ContainsIndex(model_index)) { - TabContents* contents = model_->GetTabContentsAt(model_index); + int tab_index = GetIndexOfTab(tab); + if (model_->ContainsIndex(tab_index)) { + TabContents* contents = model_->GetTabContentsAt(tab_index); if (contents) UserMetrics::RecordAction(UserMetricsAction("CloseTab_Mouse"), contents->profile()); - if (model_index + 1 != model_->count() && model_->count() > 1) { - Tab* last_tab = GetTabAtModelIndex(model_->count() - 2); - // Limit the width available to the TabStrip for laying out Tabs, so that - // Tabs are not resized until a later time (when the mouse pointer leaves - // the TabStrip). - available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); - needs_resize_layout_ = true; - AddMessageLoopObserver(); - } else if (model_->count() > 1) { - Tab* last_tab = GetTabAtModelIndex(model_->count() - 1); - // Limit the width available to the TabStrip for laying out Tabs, so that - // Tabs are not resized until a later time (when the mouse pointer leaves - // the TabStrip). - available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); - needs_resize_layout_ = true; - AddMessageLoopObserver(); - } + Tab* last_tab = GetTabAt(GetTabCount() - 1); + // Limit the width available to the TabStrip for laying out Tabs, so that + // Tabs are not resized until a later time (when the mouse pointer leaves + // the TabStrip). + available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); + needs_resize_layout_ = true; + AddMessageLoopObserver(); // Note that the next call might not close the tab (because of unload // hanlders or if the delegate veto the close). - model_->CloseTabContentsAt(model_index); + model_->CloseTabContentsAt(tab_index); } } bool TabStrip::IsCommandEnabledForTab( TabStripModel::ContextMenuCommand command_id, const Tab* tab) const { - int model_index = GetModelIndexOfTab(tab); - if (model_->ContainsIndex(model_index)) - return model_->IsContextMenuCommandEnabled(model_index, command_id); + int index = GetIndexOfTab(tab); + if (model_->ContainsIndex(index)) + return model_->IsContextMenuCommandEnabled(index, command_id); return false; } void TabStrip::ExecuteCommandForTab( TabStripModel::ContextMenuCommand command_id, Tab* tab) { - int model_index = GetModelIndexOfTab(tab); - if (model_->ContainsIndex(model_index)) - model_->ExecuteContextMenuCommand(model_index, command_id); -} - -void TabStrip::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { - AnimationType last_type = animation_type_; - - ResetAnimationState(false); - - if (last_type == ANIMATION_NEW_TAB_2) - NewTabAnimation2Done(); + int index = GetIndexOfTab(tab); + if (model_->ContainsIndex(index)) + model_->ExecuteContextMenuCommand(index, command_id); } void TabStrip::StartHighlightTabsForCommand( @@ -870,13 +1320,13 @@ void TabStrip::StartHighlightTabsForCommand( if (command_id == TabStripModel::CommandCloseTabsOpenedBy || command_id == TabStripModel::CommandCloseOtherTabs || command_id == TabStripModel::CommandCloseTabsToRight) { - int model_index = GetModelIndexOfTab(tab); - if (model_->ContainsIndex(model_index)) { + int index = GetIndexOfTab(tab); + if (model_->ContainsIndex(index)) { std::vector indices = - model_->GetIndicesClosedByCommand(model_index, command_id); + model_->GetIndicesClosedByCommand(index, command_id); for (std::vector::const_iterator i = indices.begin(); i != indices.end(); ++i) { - GetTabAtModelIndex(*i)->StartPulse(); + GetTabAtAdjustForAnimation(*i)->StartPulse(); } } } @@ -894,7 +1344,7 @@ void TabStrip::StopHighlightTabsForCommand( void TabStrip::StopAllHighlighting() { for (int i = 0; i < GetTabCount(); ++i) - GetTabAtTabDataIndex(i)->StopPulse(); + GetTabAt(i)->StopPulse(); } void TabStrip::MaybeStartDrag(Tab* tab, const views::MouseEvent& event) { @@ -904,8 +1354,8 @@ void TabStrip::MaybeStartDrag(Tab* tab, const views::MouseEvent& event) { // the user is dragging. if (IsAnimating() || tab->closing() || !HasAvailableDragActions()) return; - int model_index = GetModelIndexOfTab(tab); - if (!model_->ContainsIndex(model_index)) { + int index = GetIndexOfTab(tab); + if (!model_->ContainsIndex(index)) { CHECK(false); return; } @@ -1013,18 +1463,15 @@ void TabStrip::DidProcessEvent(GdkEvent* event) { void TabStrip::Init() { SetID(VIEW_ID_TAB_STRIP); model_->AddObserver(this); - newtab_button_bounds_.SetRect(0, 0, kNewTabButtonWidth, kNewTabButtonHeight); - if (browser_defaults::kSizeTabButtonToTopOfTabStrip) { - newtab_button_bounds_.set_height( - kNewTabButtonHeight + kNewTabButtonVOffset); - } + newtab_button_size_.SetSize(kNewTabButtonWidth, kNewTabButtonHeight); + if (browser_defaults::kSizeTabButtonToTopOfTabStrip) + newtab_button_size_.set_height(kNewTabButtonHeight + kNewTabButtonVOffset); if (drop_indicator_width == 0) { // Direction doesn't matter, both images are the same size. SkBitmap* drop_image = GetDropArrowImage(true); drop_indicator_width = drop_image->width(); drop_indicator_height = drop_image->height(); } - bounds_animator_.set_observer(this); } void TabStrip::LoadNewTabButtonImage() { @@ -1054,14 +1501,20 @@ void TabStrip::LoadNewTabButtonImage() { delete tp; } -Tab* TabStrip::GetTabAtTabDataIndex(int tab_data_index) const { - DCHECK_GE(tab_data_index, 0); - DCHECK_LT(tab_data_index, GetTabCount()); - return tab_data_[tab_data_index].tab; +Tab* TabStrip::GetTabAt(int index) const { + DCHECK_GE(index, 0); + DCHECK_LT(index, GetTabCount()); + return tab_data_.at(index).tab; } -Tab* TabStrip::GetTabAtModelIndex(int model_index) const { - return GetTabAtTabDataIndex(ModelIndexToTabDataIndex(model_index)); +Tab* TabStrip::GetTabAtAdjustForAnimation(int index) const { + if (active_animation_.get() && + active_animation_->type() == TabAnimation::REMOVE && + index >= + static_cast(active_animation_.get())->index()) { + index++; + } + return GetTabAt(index); } int TabStrip::GetTabCount() const { @@ -1094,7 +1547,7 @@ void TabStrip::GetDesiredTabWidths(int tab_count, int available_width; if (available_width_for_tabs_ < 0) { available_width = width(); - available_width -= (kNewTabButtonHOffset + newtab_button_bounds_.width()); + available_width -= (kNewTabButtonHOffset + newtab_button_size_.width()); } else { // Interesting corner case: if |available_width_for_tabs_| > the result // of the calculation in the conditional arm above, the strip is in @@ -1154,6 +1607,14 @@ void TabStrip::GetDesiredTabWidths(int tab_count, } } +int TabStrip::GetTabHOffset(int tab_index) { + if (tab_index < GetTabCount() && GetTabAt(tab_index - 1)->mini() && + !GetTabAt(tab_index)->mini()) { + return mini_to_non_mini_gap_ + kTabHOffset; + } + return kTabHOffset; +} + void TabStrip::ResizeLayoutTabs() { // We've been called back after the TabStrip has been emptied out (probably // just prior to the window being destroyed). We need to do nothing here or @@ -1174,7 +1635,7 @@ void TabStrip::ResizeLayoutTabs() { // mini-tabs have the same width), so there is nothing to do. return; } - Tab* first_tab = GetTabAtTabDataIndex(mini_tab_count); + Tab* first_tab = GetTabAt(mini_tab_count); double unselected, selected; GetDesiredTabWidths(GetTabCount(), mini_tab_count, &unselected, &selected); int w = Round(first_tab->IsSelected() ? selected : selected); @@ -1196,7 +1657,7 @@ bool TabStrip::IsCursorInTabStripZone() const { DWORD pos = GetMessagePos(); gfx::Point cursor_point(pos); #elif defined(OS_LINUX) - // TODO(sky): make sure this is right with multiple monitors. + // TODO: make sure this is right with multiple monitors. GdkScreen* screen = gdk_screen_get_default(); GdkDisplay* display = gdk_screen_get_display(screen); gint x, y; @@ -1227,13 +1688,14 @@ gfx::Rect TabStrip::GetDropBounds(int drop_index, DCHECK(drop_index != -1); int center_x; if (drop_index < GetTabCount()) { - Tab* tab = GetTabAtTabDataIndex(drop_index); + Tab* tab = GetTabAt(drop_index); + // TODO(sky): update these for mini-tabs. if (drop_before) center_x = tab->x() - (kTabHOffset / 2); else center_x = tab->x() + (tab->width() / 2); } else { - Tab* last_tab = GetTabAtTabDataIndex(drop_index - 1); + Tab* last_tab = GetTabAt(drop_index - 1); center_x = last_tab->x() + last_tab->width() + (kTabHOffset / 2); } @@ -1269,7 +1731,7 @@ void TabStrip::UpdateDropIndex(const DropTargetEvent& event) { const int x = MirroredXCoordinateInsideView(event.x()); // We don't allow replacing the urls of mini-tabs. for (int i = GetMiniTabCount(); i < GetTabCount(); ++i) { - Tab* tab = GetTabAtTabDataIndex(i); + Tab* tab = GetTabAt(i); const int tab_max_x = tab->x() + tab->width(); const int hot_width = tab->width() / 3; if (x < tab_max_x) { @@ -1287,26 +1749,25 @@ void TabStrip::UpdateDropIndex(const DropTargetEvent& event) { SetDropIndex(GetTabCount(), true); } -void TabStrip::SetDropIndex(int tab_data_index, bool drop_before) { - if (tab_data_index == -1) { +void TabStrip::SetDropIndex(int index, bool drop_before) { + if (index == -1) { if (drop_info_.get()) drop_info_.reset(NULL); return; } - if (drop_info_.get() && drop_info_->drop_index == tab_data_index && + if (drop_info_.get() && drop_info_->drop_index == index && drop_info_->drop_before == drop_before) { return; } bool is_beneath; - gfx::Rect drop_bounds = GetDropBounds(tab_data_index, drop_before, - &is_beneath); + gfx::Rect drop_bounds = GetDropBounds(index, drop_before, &is_beneath); if (!drop_info_.get()) { - drop_info_.reset(new DropInfo(tab_data_index, drop_before, !is_beneath)); + drop_info_.reset(new DropInfo(index, drop_before, !is_beneath)); } else { - drop_info_->drop_index = tab_data_index; + drop_info_->drop_index = index; drop_info_->drop_before = drop_before; if (is_beneath == drop_info_->point_down) { drop_info_->point_down = !is_beneath; @@ -1383,19 +1844,8 @@ TabStrip::DropInfo::~DropInfo() { // - Tab reorder void TabStrip::GenerateIdealBounds() { int tab_count = GetTabCount(); - int non_closing_tab_count = 0; - int mini_tab_count = 0; - for (int i = 0; i < tab_count; ++i) { - if (!tab_data_[i].tab->closing()) { - ++non_closing_tab_count; - if (tab_data_[i].tab->mini()) - mini_tab_count++; - } - } - double unselected, selected; - GetDesiredTabWidths(non_closing_tab_count, mini_tab_count, &unselected, - &selected); + GetDesiredTabWidths(tab_count, GetMiniTabCount(), &unselected, &selected); current_unselected_width_ = unselected; current_selected_width_ = selected; @@ -1404,259 +1854,139 @@ void TabStrip::GenerateIdealBounds() { // selected state or the number of tabs in the strip! int tab_height = Tab::GetStandardSize().height(); double tab_x = 0; - bool last_was_mini = false; for (int i = 0; i < tab_count; ++i) { - if (!tab_data_[i].tab->closing()) { - Tab* tab = GetTabAtTabDataIndex(i); - double tab_width = unselected; - if (tab->mini()) { - tab_width = Tab::GetMiniWidth(); - } else { - if (last_was_mini) { - // Give a bigger gap between mini and non-mini tabs. - tab_x += mini_to_non_mini_gap_; - } - if (tab->IsSelected()) - tab_width = selected; - } - double end_of_tab = tab_x + tab_width; - int rounded_tab_x = Round(tab_x); - tab_data_[i].ideal_bounds = - gfx::Rect(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, + Tab* tab = GetTabAt(i); + double tab_width = unselected; + if (tab->mini()) + tab_width = Tab::GetMiniWidth(); + else if (tab->IsSelected()) + tab_width = selected; + double end_of_tab = tab_x + tab_width; + int rounded_tab_x = Round(tab_x); + gfx::Rect state(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, tab_height); - tab_x = end_of_tab + kTabHOffset; - last_was_mini = tab->mini(); - } + tab_data_.at(i).ideal_bounds = state; + tab_x = end_of_tab + GetTabHOffset(i + 1); } +} - // Update bounds of new tab button. - int new_tab_x; - int new_tab_y = browser_defaults::kSizeTabButtonToTopOfTabStrip ? +void TabStrip::LayoutNewTabButton(double last_tab_right, + double unselected_width) { + int delta = abs(Round(unselected_width) - Tab::GetStandardSize().width()); + int v_offset = browser_defaults::kSizeTabButtonToTopOfTabStrip ? 0 : kNewTabButtonVOffset; - if (abs(Round(unselected) - Tab::GetStandardSize().width()) > 1 && - available_width_for_tabs_ == -1) { + if (delta > 1 && !needs_resize_layout_) { // We're shrinking tabs, so we need to anchor the New Tab button to the // right edge of the TabStrip's bounds, rather than the right edge of the // right-most Tab, otherwise it'll bounce when animating. - new_tab_x = width() - newtab_button_bounds_.width(); + newtab_button_->SetBounds(width() - newtab_button_size_.width(), + v_offset, + newtab_button_size_.width(), + newtab_button_size_.height()); } else { - new_tab_x = Round(tab_x - kTabHOffset) + kNewTabButtonHOffset; - } - newtab_button_bounds_.set_origin(gfx::Point(new_tab_x, new_tab_y)); -} - -void TabStrip::NewTabAnimation1Done() { - int tab_data_index = static_cast(tab_data_.size() - 1); - Tab* tab = GetTabAtTabDataIndex(tab_data_index); - - gfx::Rect old_tab_bounds = tab->bounds(); - - GenerateIdealBounds(); - - gfx::Rect& end_bounds = tab_data_[tab_data_index].ideal_bounds; - end_bounds.Offset(kNewTabOvershoot, 0); - - int x = old_tab_bounds.right() - end_bounds.width(); - int w = end_bounds.width(); - if (x < 0) { - w += x; - x = 0; - } - tab->SetBounds(x, old_tab_bounds.y(), w, end_bounds.height()); - - AnimateToIdealBounds(); - - animation_type_ = ANIMATION_NEW_TAB_2; - tab->set_render_as_new_tab(false); - tab->set_render_unselected(true); - tab->set_alpha(0); - - // BoundsAnimator takes ownership of NewTabAlphaDelegate. - bounds_animator_.SetAnimationDelegate(tab, new NewTabAlphaDelegate(tab), - true); -} - -void TabStrip::NewTabAnimation2Done() { - animation_type_ = ANIMATION_NEW_TAB_3; - - GenerateIdealBounds(); - - AnimateToIdealBounds(); - - SlideAnimation* animation = new SlideAnimation(NULL); - animation->SetSlideDuration(kNewTab3DurationMs); - animation->SetTweenType(SlideAnimation::EASE_IN_OUT); - - // BoundsAnimator takes ownership of animation. - bounds_animator_.SetAnimationForView(tab_data_.back().tab, animation); -} - -void TabStrip::AnimateToIdealBounds() { - for (size_t i = 0; i < tab_data_.size(); ++i) { - if (!tab_data_[i].tab->closing()) { - bounds_animator_.AnimateViewTo(tab_data_[i].tab, - tab_data_[i].ideal_bounds, - false); - } - } - - if (animation_type_ != ANIMATION_NEW_TAB_3) { - bounds_animator_.AnimateViewTo(newtab_button_, - newtab_button_bounds_, - false); + newtab_button_->SetBounds( + Round(last_tab_right - kTabHOffset) + kNewTabButtonHOffset, + v_offset, newtab_button_size_.width(), newtab_button_size_.height()); } } -bool TabStrip::ShouldStartIntertTabAnimationAtEnd(int model_index, - bool foreground) { - return foreground && (model_index + 1 == model_->count()) && - (model_->GetTabContentsAt(model_index)->GetURL() == - GURL(chrome::kChromeUINewTabURL)); +// Called from: +// - animation tick +void TabStrip::AnimationLayout(double unselected_width) { + int tab_height = Tab::GetStandardSize().height(); + double tab_x = 0; + for (int i = 0; i < GetTabCount(); ++i) { + TabAnimation* animation = active_animation_.get(); + if (animation) + tab_x += animation->GetGapWidth(i); + double tab_width = TabAnimation::GetCurrentTabWidth(this, animation, i); + double end_of_tab = tab_x + tab_width; + int rounded_tab_x = Round(tab_x); + Tab* tab = GetTabAt(i); + tab->SetBounds(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, + tab_height); + tab_x = end_of_tab + GetTabHOffset(i + 1); + } + LayoutNewTabButton(tab_x, unselected_width); + SchedulePaint(); } void TabStrip::StartResizeLayoutAnimation() { - ResetAnimationState(true); - GenerateIdealBounds(); - AnimateToIdealBounds(); + if (active_animation_.get()) + active_animation_->Stop(); + active_animation_.reset(new ResizeLayoutAnimation(this)); + active_animation_->Start(); } -void TabStrip::StartInsertTabAnimationAtEnd() { - ResetAnimationState(true); - +void TabStrip::StartInsertTabAnimation(int index) { // The TabStrip can now use its entire width to lay out Tabs. available_width_for_tabs_ = -1; - - animation_type_ = ANIMATION_NEW_TAB_1; - - GenerateIdealBounds(); - - int tab_data_index = ModelIndexToTabDataIndex(model_->count() - 1); - Tab* tab = tab_data_[tab_data_index].tab; - tab->SizeToNewTabButtonImages(); - tab->SetBounds(newtab_button_->x() + - (newtab_button_->width() - tab->width()) / 2, - tab_data_[tab_data_index].ideal_bounds.y(), - tab->width(), tab->height()); - tab->set_render_as_new_tab(true); - - new_tab_timer_.Start(base::TimeDelta::FromMilliseconds(kNewTabDurationMs), - this, &TabStrip::NewTabAnimation1Done); + if (active_animation_.get()) + active_animation_->Stop(); + active_animation_.reset(new InsertTabAnimation(this, index)); + active_animation_->Start(); } -void TabStrip::StartInsertTabAnimation(int model_index) { - ResetAnimationState(true); - - // The TabStrip can now use its entire width to lay out Tabs. - available_width_for_tabs_ = -1; - - GenerateIdealBounds(); - - int tab_data_index = ModelIndexToTabDataIndex(model_index); - Tab* tab = tab_data_[tab_data_index].tab; - if (model_index == 0) { - tab->SetBounds(0, tab_data_[tab_data_index].ideal_bounds.y(), 0, - tab_data_[tab_data_index].ideal_bounds.height()); - } else { - Tab* last_tab = tab_data_[tab_data_index - 1].tab; - tab->SetBounds(last_tab->bounds().right() + kTabHOffset, - tab_data_[tab_data_index].ideal_bounds.y(), 0, - tab_data_[tab_data_index].ideal_bounds.height()); +void TabStrip::StartRemoveTabAnimation(int index, TabContents* contents) { + if (active_animation_.get()) { + // Some animations (e.g. MoveTabAnimation) cause there to be a Layout when + // they're completed (which includes canceled). Since |tab_data_| is now + // inconsistent with TabStripModel, doing this Layout will crash now, so + // we ask the MoveTabAnimation to skip its Layout (the state will be + // corrected by the RemoveTabAnimation we're about to initiate). + active_animation_->set_layout_on_completion(false); + active_animation_->Stop(); } - - AnimateToIdealBounds(); + active_animation_.reset(new RemoveTabAnimation(this, index, contents)); + active_animation_->Start(); } -void TabStrip::StartRemoveTabAnimation(int model_index) { - ResetAnimationState(true); - - // Mark the tab as closing. - int tab_data_index = ModelIndexToTabDataIndex(model_index); - Tab* tab = tab_data_[tab_data_index].tab; - tab->set_closing(true); - - // Start an animation for the tabs. - GenerateIdealBounds(); - AnimateToIdealBounds(); - - // Animate the tab being closed to 0x0. - gfx::Rect tab_bounds = tab->bounds(); - tab_bounds.set_width(0); - bounds_animator_.AnimateViewTo(tab, tab_bounds, false); - - // Register delegate to do cleanup when done, BoundsAnimator takes - // ownership of RemoveTabDelegate. - bounds_animator_.SetAnimationDelegate(tab, new RemoveTabDelegate(this, tab), - true); +void TabStrip::StartMoveTabAnimation(int from_index, int to_index) { + if (active_animation_.get()) + active_animation_->Stop(); + active_animation_.reset(new MoveTabAnimation(this, from_index, to_index)); + active_animation_->Start(); } -void TabStrip::StartMoveTabAnimation(int from_model_index, - int to_model_index) { - ResetAnimationState(true); - - int from_tab_data_index = ModelIndexToTabDataIndex(from_model_index); - - Tab* tab = tab_data_[from_tab_data_index].tab; - tab_data_.erase(tab_data_.begin() + from_tab_data_index); - - TabData data = {tab, gfx::Rect()}; - tab->set_mini(model_->IsMiniTab(to_model_index)); - //tab->set_app(model_->IsAppTab(to_model_index)); - tab->SetBlocked(model_->IsTabBlocked(to_model_index)); - - int to_tab_data_index = ModelIndexToTabDataIndex(to_model_index); - - tab_data_.insert(tab_data_.begin() + to_tab_data_index, data); - if (tab->phantom() != model_->IsPhantomTab(to_model_index)) - tab->set_phantom(!tab->phantom()); - - GenerateIdealBounds(); - AnimateToIdealBounds(); +void TabStrip::StartMiniTabAnimation(int index) { + if (active_animation_.get()) + active_animation_->Stop(); + active_animation_.reset(new MiniTabAnimation(this, index)); + active_animation_->Start(); } -void TabStrip::StartMiniTabAnimation() { - ResetAnimationState(true); - - GenerateIdealBounds(); - AnimateToIdealBounds(); +void TabStrip::StartMiniMoveTabAnimation(int from_index, + int to_index, + const gfx::Rect& start_bounds) { + if (active_animation_.get()) + active_animation_->Stop(); + active_animation_.reset( + new MiniMoveAnimation(this, from_index, to_index, start_bounds)); + active_animation_->Start(); } -void TabStrip::StopAnimating(bool layout) { - if (!IsAnimating()) - return; - - new_tab_timer_.Stop(); +void TabStrip::FinishAnimation(TabStrip::TabAnimation* animation, + bool layout) { + active_animation_.reset(NULL); - if (bounds_animator_.IsAnimating()) { - // Cancelling the animation triggers OnBoundsAnimatorDone, which invokes - // ResetAnimationState. - bounds_animator_.Cancel(); - } else { - ResetAnimationState(false); - } - - DCHECK(!IsAnimating()); + // Reset the animation state of each tab. + for (int i = 0, count = GetTabCount(); i < count; ++i) + GetTabAt(i)->set_animating_mini_change(false); if (layout) Layout(); } -void TabStrip::ResetAnimationState(bool stop_new_tab_timer) { - if (animation_type_ == ANIMATION_NEW_TAB_2) - newtab_button_->SchedulePaint(); - - if (stop_new_tab_timer) - new_tab_timer_.Stop(); - - animation_type_ = ANIMATION_DEFAULT; - - // Reset the animation state of each tab. - for (int i = 0, count = GetTabCount(); i < count; ++i) { - Tab* tab = GetTabAtTabDataIndex(i); - tab->set_animating_mini_change(false); - tab->set_render_as_new_tab(false); - tab->set_render_unselected(false); - tab->set_alpha(1); +int TabStrip::GetIndexOfTab(const Tab* tab) const { + for (int i = 0, index = 0; i < GetTabCount(); ++i, ++index) { + Tab* current_tab = GetTabAt(i); + if (current_tab->closing()) { + --index; + } else if (current_tab == tab) { + return index; + } } + return -1; } int TabStrip::GetMiniTabCount() const { @@ -1681,21 +2011,22 @@ bool TabStrip::IsPointInTab(Tab* tab, return tab->HitTest(point_in_tab_coords); } -void TabStrip::RemoveTab(Tab* tab) { - int tab_data_index = TabDataIndexOfTab(tab); - - DCHECK(tab_data_index != -1); +void TabStrip::RemoveTabAt(int index) { + Tab* removed = tab_data_.at(index).tab; // Remove the Tab from the TabStrip's list... - tab_data_.erase(tab_data_.begin() + tab_data_index); + tab_data_.erase(tab_data_.begin() + index); // If the TabContents being detached was removed as a result of a drag // gesture from its corresponding Tab, we don't want to remove the Tab from // the child list, because if we do so it'll stop receiving events and the // drag will stall. So we only remove if a drag isn't active, or the Tab // was for some other TabContents. - if (!IsDragSessionActive() || !drag_controller_->IsDragSourceTab(tab)) - delete tab; + if (!IsDragSessionActive() || !drag_controller_->IsDragSourceTab(removed)) { + removed->GetParent()->RemoveChildView(removed); + delete removed; + } + GenerateIdealBounds(); } void TabStrip::HandleGlobalMouseMoveEvent() { @@ -1718,40 +2049,8 @@ void TabStrip::HandleGlobalMouseMoveEvent() { bool TabStrip::HasPhantomTabs() const { for (int i = 0; i < GetTabCount(); ++i) { - if (GetTabAtTabDataIndex(i)->phantom()) + if (GetTabAt(i)->phantom()) return true; } return false; } - -int TabStrip::GetModelIndexOfTab(const Tab* tab) const { - for (int i = 0, model_index = 0; i < GetTabCount(); ++i) { - Tab* current_tab = GetTabAtTabDataIndex(i); - if (!current_tab->closing()) { - if (current_tab == tab) - return model_index; - model_index++; - } - } - return -1; -} - -int TabStrip::ModelIndexToTabDataIndex(int model_index) const { - int current_model_index = 0; - for (size_t i = 0; i < tab_data_.size(); ++i) { - if (!tab_data_[i].tab->closing()) { - if (current_model_index == model_index) - return i; - current_model_index++; - } - } - return tab_data_.size(); -} - -int TabStrip::TabDataIndexOfTab(Tab* tab) const { - for (size_t i = 0; i < tab_data_.size(); ++i) { - if (tab_data_[i].tab == tab) - return i; - } - return -1; -} diff --git a/chrome/browser/views/tabs/tab_strip.h b/chrome/browser/views/tabs/tab_strip.h index e1cbfda..af6cc34 100644 --- a/chrome/browser/views/tabs/tab_strip.h +++ b/chrome/browser/views/tabs/tab_strip.h @@ -5,16 +5,11 @@ #ifndef CHROME_BROWSER_VIEWS_TABS_TAB_STRIP_H_ #define CHROME_BROWSER_VIEWS_TABS_TAB_STRIP_H_ -#include "app/animation_container.h" #include "base/message_loop.h" -#include "base/ref_counted.h" -#include "base/timer.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/views/tabs/base_tab_strip.h" #include "chrome/browser/views/tabs/tab.h" #include "gfx/point.h" -#include "gfx/rect.h" -#include "views/animation/bounds_animator.h" #include "views/controls/button/image_button.h" class DraggedTabController; @@ -47,8 +42,7 @@ class TabStrip : public BaseTabStrip, public TabStripModelObserver, public Tab::TabDelegate, public views::ButtonListener, - public MessageLoopForUI::Observer, - public views::BoundsAnimatorObserver { + public MessageLoopForUI::Observer { public: explicit TabStrip(TabStripModel* model); virtual ~TabStrip(); @@ -68,7 +62,7 @@ class TabStrip : public BaseTabStrip, void DestroyDraggedSourceTab(Tab* tab); // Retrieves the ideal bounds for the Tab at the specified index. - gfx::Rect GetIdealBounds(int tab_data_index); + gfx::Rect GetIdealBounds(int index); // Returns the currently selected tab. Tab* GetSelectedTab() const; @@ -109,9 +103,6 @@ class TabStrip : public BaseTabStrip, virtual views::View* GetViewForPoint(const gfx::Point& point); virtual void ThemeChanged(); - // BoundsAnimator::Observer overrides: - virtual void OnBoundsAnimatorDone(views::BoundsAnimator* animator); - protected: // Creates a new tab. virtual Tab* CreateTab(); @@ -123,24 +114,21 @@ class TabStrip : public BaseTabStrip, // TabStripModelObserver implementation: virtual void TabInsertedAt(TabContents* contents, - int model_index, + int index, bool foreground); - virtual void TabDetachedAt(TabContents* contents, int model_index); + virtual void TabDetachedAt(TabContents* contents, int index); virtual void TabSelectedAt(TabContents* old_contents, TabContents* contents, - int model_index, + int index, bool user_gesture); - virtual void TabMoved(TabContents* contents, - int from_model_index, - int to_model_index); - virtual void TabChangedAt(TabContents* contents, - int model_index, + virtual void TabMoved(TabContents* contents, int from_index, int to_index); + virtual void TabChangedAt(TabContents* contents, int index, TabChangeType change_type); virtual void TabReplacedAt(TabContents* old_contents, TabContents* new_contents, - int model_index); - virtual void TabMiniStateChanged(TabContents* contents, int model_index); - virtual void TabBlockedStateChanged(TabContents* contents, int model_index); + int index); + virtual void TabMiniStateChanged(TabContents* contents, int index); + virtual void TabBlockedStateChanged(TabContents* contents, int index); // Tab::Delegate implementation: virtual bool IsTabSelected(const Tab* tab) const; @@ -177,70 +165,22 @@ class TabStrip : public BaseTabStrip, static const int mini_to_non_mini_gap_; private: - class RemoveTabDelegate; + class InsertTabAnimation; + class MiniMoveAnimation; + class MiniTabAnimation; + class MoveTabAnimation; + class RemoveTabAnimation; + class ResizeLayoutAnimation; + class TabAnimation; friend class DraggedTabController; - - // AnimationType used for tracking animations that require additional - // state beyond just animating the bounds of a view. - // - // Currently the only animation special cased is that of inserting the new tab - // page at the end of the tab strip. Here's the steps that take place when - // this happens. - // . The newly inserted tab is set to render for the new tab animation - // |set_render_as_new_tab|. The timer new_tab_timer_ is used to determine - // when to turn this off. This is represented by state ANIMATION_NEW_TAB_1. - // . The new tab is rendered in the background with an ever increasing alpha - // value and the tab goes slightly past the new tab button. The new tab - // button is not visible during this animation. This is represented by the - // state ANIMATION_NEW_TAB_2. - // . The new tab is animated to its final position and the new tab button is - // rendered beneath the selected tab. This is represented by the state - // ANIMATION_NEW_TAB_3. - enum AnimationType { - ANIMATION_DEFAULT, - - ANIMATION_NEW_TAB_1, - ANIMATION_NEW_TAB_2, - ANIMATION_NEW_TAB_3 - }; - - // Used during a drop session of a url. Tracks the position of the drop as - // well as a window used to highlight where the drop occurs. - struct DropInfo { - DropInfo(int index, bool drop_before, bool paint_down); - ~DropInfo(); - - // Index of the tab to drop on. If drop_before is true, the drop should - // occur between the tab at drop_index - 1 and drop_index. - // WARNING: if drop_before is true it is possible this will == tab_count, - // which indicates the drop should create a new tab at the end of the tabs. - int drop_index; - bool drop_before; - - // Direction the arrow should point in. If true, the arrow is displayed - // above the tab and points down. If false, the arrow is displayed beneath - // the tab and points up. - bool point_down; - - // Renders the drop indicator. - // TODO(beng): should be views::Widget. -#if defined(OS_WIN) - views::WidgetWin* arrow_window; -#else - views::WidgetGtk* arrow_window; -#endif - views::ImageView* arrow_view; - - private: - DISALLOW_COPY_AND_ASSIGN(DropInfo); - }; - - // The Tabs we contain, and their last generated "good" bounds. - struct TabData { - Tab* tab; - gfx::Rect ideal_bounds; - }; + friend class InsertTabAnimation; + friend class MiniMoveAnimation; + friend class MiniTabAnimation; + friend class MoveTabAnimation; + friend class RemoveTabAnimation; + friend class ResizeLayoutAnimation; + friend class TabAnimation; TabStrip(); void Init(); @@ -248,9 +188,9 @@ class TabStrip : public BaseTabStrip, // Set the images for the new tab button. void LoadNewTabButtonImage(); - // Retrieves the Tab at the specified index. Remember, the specified index - // is in terms of tab_data, *not* the model. - Tab* GetTabAtTabDataIndex(int tab_data_index) const; + // Retrieves the Tab at the specified index. Take care in using this, you may + // need to use GetTabAtAdjustForAnimation. + Tab* GetTabAt(int index) const; // Returns the tab at the specified index. If a remove animation is on going // and the index is >= the index of the tab being removed, the index is @@ -258,13 +198,10 @@ class TabStrip : public BaseTabStrip, // do not line up with the indices of the view. This method adjusts the index // accordingly. // - // Use this instead of GetTabAtTabDataIndex if the index comes from the model. - Tab* GetTabAtModelIndex(int model_index) const; + // Use this instead of GetTabAt if the index comes from the model. + Tab* GetTabAtAdjustForAnimation(int index) const; // Gets the number of Tabs in the collection. - // WARNING: this is the number of tabs displayed by the tabstrip, which if - // an animation is ongoing is not necessarily the same as the number of tabs - // in the model. int GetTabCount() const; // Returns the number of mini-tabs. @@ -287,6 +224,9 @@ class TabStrip : public BaseTabStrip, double* unselected_width, double* selected_width) const; + // Returns the horizontal offset before the tab at |tab_index|. + int GetTabHOffset(int tab_index); + // Perform an animated resize-relayout of the TabStrip immediately. void ResizeLayoutTabs(); @@ -310,7 +250,7 @@ class TabStrip : public BaseTabStrip, void UpdateDropIndex(const views::DropTargetEvent& event); // Sets the location of the drop, repainting as necessary. - void SetDropIndex(int tab_data_index, bool drop_before); + void SetDropIndex(int index, bool drop_before); // Returns the drop effect for dropping a URL on the tab strip. This does // not query the data in anyway, it only looks at the source operations. @@ -328,38 +268,32 @@ class TabStrip : public BaseTabStrip, // stable representations of Tab positions. void GenerateIdealBounds(); - // Both of these are invoked when a part of the new tab animation completes. - // They configure state for the next step in the animation and start it. - void NewTabAnimation1Done(); - void NewTabAnimation2Done(); - - // Animates all the views to their ideal bounds. - // NOTE: this does *not* invoke GenerateIdealBounds, it uses the bounds - // currently set in ideal_bounds. - void AnimateToIdealBounds(); + // Lays out the New Tab button, assuming the right edge of the last Tab on + // the TabStrip at |last_tab_right|. + void LayoutNewTabButton(double last_tab_right, double unselected_width); - // Returns true if a new tab inserted at specified index should start the - // new tab animation. See description above AnimationType for details on - // this animation. - bool ShouldStartIntertTabAnimationAtEnd(int model_index, bool foreground); + // A generic Layout method for various classes of TabStrip animations, + // including Insert, Remove and Resize Layout cases/ + void AnimationLayout(double unselected_width); // Starts various types of TabStrip animations. void StartResizeLayoutAnimation(); - void StartInsertTabAnimationAtEnd(); - void StartInsertTabAnimation(int model_index); - void StartRemoveTabAnimation(int model_index); - void StartMoveTabAnimation(int from_model_index, - int to_model_index); - void StartMiniTabAnimation(); - - // Stops any ongoing animations. If |layout| is true and an animation is - // ongoing this does a layout. - void StopAnimating(bool layout); - - // Resets all state related to animations. This is invoked when an animation - // completes, prior to starting an animation or when we cancel an animation. - // If |stop_new_tab_timer| is true, |new_tab_timer_| is stopped. - void ResetAnimationState(bool stop_new_tab_timer); + void StartInsertTabAnimation(int index); + void StartRemoveTabAnimation(int index, TabContents* contents); + void StartMoveTabAnimation(int from_index, int to_index); + void StartMiniTabAnimation(int index); + void StartMiniMoveTabAnimation(int from_index, + int to_index, + const gfx::Rect& start_bounds); + + // Notifies the TabStrip that the specified TabAnimation has completed. + // Optionally a full Layout will be performed, specified by |layout|. + void FinishAnimation(TabAnimation* animation, bool layout); + + // Finds the index of the TabContents corresponding to |tab| in our + // associated TabStripModel, or -1 if there is none (e.g. the specified |tab| + // is being animated closed). + int GetIndexOfTab(const Tab* tab) const; // Calculates the available width for tabs, assuming a Tab is to be closed. int GetAvailableWidthForTabs(Tab* last_tab) const; @@ -368,9 +302,9 @@ class TabStrip : public BaseTabStrip, // hit-test region of the specified Tab. bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords); - // Cleans up the Tab from the TabStrip. This is called from the tab animation - // code and is not a general-purpose method. - void RemoveTab(Tab* tab); + // Cleans up the Tab from the TabStrip at the specified |index|. This is + // called from the tab animation code and is not a general-purpose method. + void RemoveTabAt(int index); // Called from the message loop observer when a mouse movement has occurred // anywhere over our containing window. @@ -379,19 +313,6 @@ class TabStrip : public BaseTabStrip, // Returns true if any of the tabs are phantom. bool HasPhantomTabs() const; - // Returns the index of the specified tab in the model coordiate system, or - // -1 if tab is closing or not in |tab_data_|. - int GetModelIndexOfTab(const Tab* tab) const; - - // Returns the index into |tab_data_| corresponding to the index from the - // TabStripModel, or |tab_data_.size()| if there is no tab representing - // |model_index|. - int ModelIndexToTabDataIndex(int model_index) const; - - // Returns the index into |tab_data_| corresponding to the specified tab, or - // -1 if the tab isn't in |tab_data_|. - int TabDataIndexOfTab(Tab* tab) const; - // -- Member Variables ------------------------------------------------------ // Our model. @@ -410,9 +331,7 @@ class TabStrip : public BaseTabStrip, // The "New Tab" button. views::ImageButton* newtab_button_; - - // Ideal bounds of the new tab button. - gfx::Rect newtab_button_bounds_; + gfx::Size newtab_button_size_; // The current widths of various types of tabs. We save these so that, as // users close tabs while we're holding them at the same size, we can lay out @@ -440,6 +359,37 @@ class TabStrip : public BaseTabStrip, static const int kNewTabButtonWidth = 28; static const int kNewTabButtonHeight = 18; + // Used during a drop session of a url. Tracks the position of the drop as + // well as a window used to highlight where the drop occurs. + struct DropInfo { + DropInfo(int index, bool drop_before, bool paint_down); + ~DropInfo(); + + // Index of the tab to drop on. If drop_before is true, the drop should + // occur between the tab at drop_index - 1 and drop_index. + // WARNING: if drop_before is true it is possible this will == tab_count, + // which indicates the drop should create a new tab at the end of the tabs. + int drop_index; + bool drop_before; + + // Direction the arrow should point in. If true, the arrow is displayed + // above the tab and points down. If false, the arrow is displayed beneath + // the tab and points up. + bool point_down; + + // Renders the drop indicator. + // TODO(beng): should be views::Widget. +#if defined(OS_WIN) + views::WidgetWin* arrow_window; +#else + views::WidgetGtk* arrow_window; +#endif + views::ImageView* arrow_view; + + private: + DISALLOW_COPY_AND_ASSIGN(DropInfo); + }; + // Valid for the lifetime of a drag over us. scoped_ptr drop_info_; @@ -447,19 +397,15 @@ class TabStrip : public BaseTabStrip, // the drag session. scoped_ptr drag_controller_; + // The Tabs we contain, and their last generated "good" bounds. + struct TabData { + Tab* tab; + gfx::Rect ideal_bounds; + }; std::vector tab_data_; - // To ensure all tabs pulse at the same time they share the same animation - // container. This is that animation container. - scoped_refptr animation_container_; - - views::BoundsAnimator bounds_animator_; - - // Used for stage 1 of new tab animation. - base::OneShotTimer new_tab_timer_; - - // Set for special animations. - AnimationType animation_type_; + // The currently running animation. + scoped_ptr active_animation_; DISALLOW_COPY_AND_ASSIGN(TabStrip); }; diff --git a/chrome/browser/views/toolbar_star_toggle.cc b/chrome/browser/views/toolbar_star_toggle.cc new file mode 100644 index 0000000..710d6fa --- /dev/null +++ b/chrome/browser/views/toolbar_star_toggle.cc @@ -0,0 +1,133 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/views/toolbar_star_toggle.h" + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_theme_provider.h" +#include "chrome/browser/bubble_positioner.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/views/browser_dialogs.h" +#include "chrome/browser/view_ids.h" +#include "googleurl/src/gurl.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" + +using base::TimeTicks; + +// The amount of time (in milliseconds) between when the bubble closes and when +// pressing on the button again does something. Yes, this is a hackish. I tried +// many different options, all to no avail: +// . Keying off mouse activation: this didn't work as there is no way to know +// which window receives the activation. Additionally once the mouse +// activation occurs we have no way to tie the next mouse event to the mouse +// activation. +// . Watching all events as we dispatch them in the MessageLoop. Mouse +// activation isn't an observable event though. +// Ideally we could use mouse capture for this, but we can't use mouse capture +// with the bubble because it has other native windows. +static const int64 kDisallowClickMS = 40; + +ToolbarStarToggle::ToolbarStarToggle(views::ButtonListener* listener) + : ToggleImageButton(listener), + profile_(NULL), + host_view_(NULL), + bubble_positioner_(NULL), + ignore_click_(false) { +} + +void ToolbarStarToggle::Init() { + set_tag(IDC_BOOKMARK_PAGE); + SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_STAR)); + SetToggledTooltipText(l10n_util::GetString(IDS_TOOLTIP_STARRED)); + SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_STAR)); + SetID(VIEW_ID_STAR_BUTTON); +} + +void ToolbarStarToggle::LoadImages() { + ThemeProvider* tp = profile_->GetThemeProvider(); + + // Load images. + SkColor color = tp->GetColor(BrowserThemeProvider::COLOR_BUTTON_BACKGROUND); + SkBitmap* background = tp->GetBitmapNamed(IDR_THEME_BUTTON_BACKGROUND); + + SetImage(views::CustomButton::BS_NORMAL, tp->GetBitmapNamed(IDR_STAR)); + SetImage(views::CustomButton::BS_HOT, tp->GetBitmapNamed(IDR_STAR_H)); + SetImage(views::CustomButton::BS_PUSHED, tp->GetBitmapNamed(IDR_STAR_P)); + SetImage(views::CustomButton::BS_DISABLED, tp->GetBitmapNamed(IDR_STAR_D)); + SetToggledImage(views::CustomButton::BS_NORMAL, + tp->GetBitmapNamed(IDR_STARRED)); + SetToggledImage(views::CustomButton::BS_HOT, + tp->GetBitmapNamed(IDR_STARRED_H)); + SetToggledImage(views::CustomButton::BS_PUSHED, + tp->GetBitmapNamed(IDR_STARRED_P)); + SetBackground(color, background, tp->GetBitmapNamed(IDR_STAR_MASK)); +} + +void ToolbarStarToggle::ShowStarBubble(const GURL& url, bool newly_bookmarked) { + gfx::Rect bounds(bubble_positioner_->GetLocationStackBounds()); + gfx::Point star_location; + views::View::ConvertPointToScreen(this, &star_location); + // The visual center of the star is not centered within the bounds. The star + // has a single central pixel; there are 13 pixels on the "inside" side of it + // (toward the location bar) and 16 on the "outside". This means we need to + // shift the bounds one pixel toward the location bar in order to place the + // star's outside edge at the horizontal center. However, even this isn't + // good enough in RTL mode, because the InfoBubble's arrow's central pixel is + // drawn with its left edge on the target rect center-line in both LTR and RTL + // modes. So in RTL mode, we need to shift the bounds one more pixel left, in + // order to place the star's central pixel on the right side of the bounds' + // center-line, so that the arrow's center will line up. + // + // TODO(pkasting): If the InfoBubble used mirroring transformations maybe this + // could become symmetric (-1 : 1). + bounds.set_x(star_location.x() + (UILayoutIsRightToLeft() ? -2 : 1)); + bounds.set_width(width()); + browser::ShowBookmarkBubbleView(host_view_->GetWindow(), bounds, this, + profile_, url, newly_bookmarked); +} + +bool ToolbarStarToggle::OnMousePressed(const views::MouseEvent& e) { + ignore_click_ = ((TimeTicks::Now() - bubble_closed_time_).InMilliseconds() < + kDisallowClickMS); + return ToggleImageButton::OnMousePressed(e); +} + +void ToolbarStarToggle::OnMouseReleased(const views::MouseEvent& e, + bool canceled) { + ToggleImageButton::OnMouseReleased(e, canceled); + ignore_click_ = false; +} + +void ToolbarStarToggle::OnDragDone() { + ToggleImageButton::OnDragDone(); + ignore_click_ = false; +} + +void ToolbarStarToggle::NotifyClick(const views::Event& event) { + if (!ignore_click_ && !browser::IsBookmarkBubbleViewShowing()) + ToggleImageButton::NotifyClick(event); +} + +SkBitmap ToolbarStarToggle::GetImageToPaint() { + if (browser::IsBookmarkBubbleViewShowing()) { + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + return *rb.GetBitmapNamed(IDR_STARRED_P); + } + return ImageButton::GetImageToPaint(); +} + +void ToolbarStarToggle::InfoBubbleClosing(InfoBubble* info_bubble, + bool closed_by_escape) { + SchedulePaint(); + bubble_closed_time_ = TimeTicks::Now(); +} + +bool ToolbarStarToggle::CloseOnEscape() { + return true; +} diff --git a/chrome/browser/views/toolbar_star_toggle.h b/chrome/browser/views/toolbar_star_toggle.h new file mode 100644 index 0000000..4966655 --- /dev/null +++ b/chrome/browser/views/toolbar_star_toggle.h @@ -0,0 +1,85 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_VIEWS_TOOLBAR_STAR_TOGGLE_H_ +#define CHROME_BROWSER_VIEWS_TOOLBAR_STAR_TOGGLE_H_ + +#include "base/time.h" +#include "chrome/browser/views/info_bubble.h" +#include "views/controls/button/image_button.h" + +class BubblePositioner; +class GURL; +class Profile; + +namespace views { +class ButtonListener; +class View; +} // namespace views + +// ToolbarStarToggle is used for the star button on the toolbar, allowing the +// user to star the current page. ToolbarStarToggle manages showing the +// InfoBubble and rendering the appropriate state while the bubble is visible. + +class ToolbarStarToggle : public views::ToggleImageButton, + public InfoBubbleDelegate { + public: + explicit ToolbarStarToggle(views::ButtonListener* listener); + + void set_profile(Profile* profile) { profile_ = profile; } + void set_host_view(views::View* host_view) { host_view_ = host_view; } + void set_bubble_positioner(BubblePositioner* bubble_positioner) { + bubble_positioner_ = bubble_positioner; + } + + // Sets up all labels for the button. + void Init(); + + // Sets up all images for the button. + void LoadImages(); + + // If the bubble isn't showing, shows it. + void ShowStarBubble(const GURL& url, bool newly_bookmarked); + + // Overridden to update ignore_click_ based on whether the mouse was clicked + // quickly after the bubble was hidden. + virtual bool OnMousePressed(const views::MouseEvent& e); + + // Overridden to set ignore_click_ to false. + virtual void OnMouseReleased(const views::MouseEvent& e, bool canceled); + virtual void OnDragDone(); + + protected: + // Only invokes super if ignore_click_ is true and the bubble isn't showing. + virtual void NotifyClick(const views::Event& event); + + // Overridden to so that we appear pressed while the bubble is showing. + virtual SkBitmap GetImageToPaint(); + + private: + // InfoBubbleDelegate. + virtual void InfoBubbleClosing(InfoBubble* info_bubble, + bool closed_by_escape); + virtual bool CloseOnEscape(); + + // Profile with bookmarks info. + Profile* profile_; + + // View that hosts us. + views::View* host_view_; + + // Positioner for bookmark bubble. + BubblePositioner* bubble_positioner_; + + // Time the bubble last closed. + base::TimeTicks bubble_closed_time_; + + // If true NotifyClick does nothing. This is set in OnMousePressed based on + // the amount of time between when the bubble clicked and now. + bool ignore_click_; + + DISALLOW_COPY_AND_ASSIGN(ToolbarStarToggle); +}; + +#endif // CHROME_BROWSER_VIEWS_TOOLBAR_STAR_TOGGLE_H_ diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc index e69ff0f..52854e67 100644 --- a/chrome/browser/views/toolbar_view.cc +++ b/chrome/browser/views/toolbar_view.cc @@ -4,20 +4,42 @@ #include "chrome/browser/views/toolbar_view.h" +#include +#include + +#include "app/drag_drop_types.h" #include "app/l10n_util.h" +#include "app/os_exchange_data.h" #include "app/resource_bundle.h" #include "base/command_line.h" +#include "base/keyboard_codes.h" +#include "base/logging.h" +#include "base/path_service.h" #include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/browser.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_theme_provider.h" #include "chrome/browser/browser_window.h" +#include "chrome/browser/character_encoding.h" +#include "chrome/browser/defaults.h" +#include "chrome/browser/encoding_menu_controller.h" +#include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" -#include "chrome/browser/view_ids.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/sync_ui_util.h" +#include "chrome/browser/tab_contents/navigation_controller.h" +#include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/views/bookmark_menu_button.h" #include "chrome/browser/views/browser_actions_container.h" #include "chrome/browser/views/event_utils.h" #include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/go_button.h" +#include "chrome/browser/views/location_bar_view.h" +#include "chrome/browser/views/toolbar_star_toggle.h" +#include "chrome/browser/view_ids.h" +#include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" @@ -25,7 +47,12 @@ #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" +#include "net/base/net_util.h" +#include "views/background.h" #include "views/controls/button/button_dropdown.h" +#include "views/controls/label.h" +#include "views/controls/menu/menu_2.h" +#include "views/drag_utils.h" #include "views/focus/view_storage.h" #include "views/widget/tooltip_manager.h" #include "views/window/non_client_view.h" @@ -55,8 +82,9 @@ ToolbarView::ToolbarView(Browser* browser) : model_(browser->toolbar_model()), back_(NULL), forward_(NULL), - home_(NULL), reload_(NULL), + home_(NULL), + star_(NULL), location_bar_(NULL), go_(NULL), browser_actions_(NULL), @@ -72,8 +100,9 @@ ToolbarView::ToolbarView(Browser* browser) SetID(VIEW_ID_TOOLBAR); browser_->command_updater()->AddCommandObserver(IDC_BACK, this); browser_->command_updater()->AddCommandObserver(IDC_FORWARD, this); - browser_->command_updater()->AddCommandObserver(IDC_HOME, this); browser_->command_updater()->AddCommandObserver(IDC_RELOAD, this); + browser_->command_updater()->AddCommandObserver(IDC_HOME, this); + browser_->command_updater()->AddCommandObserver(IDC_BOOKMARK_PAGE, this); if (browser->type() == Browser::TYPE_NORMAL) display_mode_ = DISPLAYMODE_NORMAL; else @@ -267,11 +296,14 @@ void ToolbarView::EnabledStateChangedForCommand(int id, bool enabled) { case IDC_FORWARD: button = forward_; break; + case IDC_RELOAD: + button = reload_; + break; case IDC_HOME: button = home_; break; - case IDC_RELOAD: - button = reload_; + case IDC_BOOKMARK_PAGE: + button = star_; break; } if (button) @@ -281,8 +313,8 @@ void ToolbarView::EnabledStateChangedForCommand(int id, bool enabled) { //////////////////////////////////////////////////////////////////////////////// // ToolbarView, views::Button::ButtonListener implementation: -void ToolbarView::ButtonPressed(views::Button* sender, - const views::Event& event) { +void ToolbarView::ButtonPressed( + views::Button* sender, const views::Event& event) { int id = sender->tag(); switch (id) { case IDC_BACK: @@ -305,6 +337,30 @@ void ToolbarView::ButtonPressed(views::Button* sender, } //////////////////////////////////////////////////////////////////////////////// +// ToolbarView, BubblePositioner implementation: + +gfx::Rect ToolbarView::GetLocationStackBounds() const { + // The number of pixels from the left or right edges of the location stack to + // "just inside the visible borders". When the omnibox bubble contents are + // aligned with this, the visible borders tacked on to the outsides will line + // up with the visible borders on the location stack. + const int kLocationStackEdgeWidth = 2; + + gfx::Point origin; + views::View::ConvertPointToScreen(star_, &origin); + gfx::Rect stack_bounds(origin.x(), origin.y(), + star_->width() + location_bar_->width() + go_->width(), + location_bar_->height()); + if (UILayoutIsRightToLeft()) { + stack_bounds.set_x( + stack_bounds.x() - location_bar_->width() - go_->width()); + } + // Inset the bounds to just inside the visible edges (see comment above). + stack_bounds.Inset(kLocationStackEdgeWidth, 0); + return stack_bounds; +} + +//////////////////////////////////////////////////////////////////////////////// // ToolbarView, NotificationObserver implementation: void ToolbarView::Observe(NotificationType type, @@ -400,12 +456,11 @@ gfx::Size ToolbarView::GetPreferredSize() { if (IsDisplayModeNormal()) { int min_width = kControlIndent + back_->GetPreferredSize().width() + forward_->GetPreferredSize().width() + kControlHorizOffset + - (show_home_button_.GetValue() ? - (home_->GetPreferredSize().width() + kControlHorizOffset) : 0) + - reload_->GetPreferredSize().width() + - browser_actions_->GetPreferredSize().width() + - go_->GetPreferredSize().width() + + reload_->GetPreferredSize().width() + (show_home_button_.GetValue() ? + (home_->GetPreferredSize().width() + kControlHorizOffset) : 0) + + star_->GetPreferredSize().width() + go_->GetPreferredSize().width() + kMenuButtonOffset + + browser_actions_->GetPreferredSize().width() + (bookmark_menu_ ? bookmark_menu_->GetPreferredSize().width() : 0) + page_menu_->GetPreferredSize().width() + app_menu_->GetPreferredSize().width() + kPaddingRight; @@ -460,18 +515,21 @@ void ToolbarView::Layout() { forward_->SetBounds(back_->x() + back_->width(), child_y, forward_->GetPreferredSize().width(), child_height); + reload_->SetBounds(forward_->x() + forward_->width() + kControlHorizOffset, + child_y, reload_->GetPreferredSize().width(), + child_height); + if (show_home_button_.GetValue()) { home_->SetVisible(true); - home_->SetBounds(forward_->x() + forward_->width() + kControlHorizOffset, + home_->SetBounds(reload_->x() + reload_->width() + kControlHorizOffset, child_y, home_->GetPreferredSize().width(), child_height); } else { home_->SetVisible(false); - home_->SetBounds(forward_->x() + forward_->width(), child_y, 0, - child_height); + home_->SetBounds(reload_->x() + reload_->width(), child_y, 0, child_height); } - reload_->SetBounds(home_->x() + home_->width() + kControlHorizOffset, child_y, - reload_->GetPreferredSize().width(), child_height); + star_->SetBounds(home_->x() + home_->width() + kControlHorizOffset, + child_y, star_->GetPreferredSize().width(), child_height); int go_button_width = go_->GetPreferredSize().width(); int browser_actions_width = browser_actions_->GetPreferredSize().width(); @@ -479,7 +537,7 @@ void ToolbarView::Layout() { int app_menu_width = app_menu_->GetPreferredSize().width(); int bookmark_menu_width = bookmark_menu_ ? bookmark_menu_->GetPreferredSize().width() : 0; - int location_x = reload_->x() + reload_->width(); + int location_x = star_->x() + star_->width(); int available_width = width() - kPaddingRight - bookmark_menu_width - app_menu_width - page_menu_width - browser_actions_width - kMenuButtonOffset - go_button_width - location_x; @@ -546,6 +604,51 @@ void ToolbarView::ThemeChanged() { } //////////////////////////////////////////////////////////////////////////////// +// ToolbarView, views::DragController implementation: + +void ToolbarView::WriteDragData(views::View* sender, + const gfx::Point& press_pt, + OSExchangeData* data) { + DCHECK(GetDragOperations(sender, press_pt) != DragDropTypes::DRAG_NONE); + + UserMetrics::RecordAction(UserMetricsAction("Toolbar_DragStar"), profile_); + + // If there is a bookmark for the URL, add the bookmark drag data for it. We + // do this to ensure the bookmark is moved, rather than creating an new + // bookmark. + TabContents* tab = browser_->GetSelectedTabContents(); + if (tab) { + if (profile_ && profile_->GetBookmarkModel()) { + const BookmarkNode* node = profile_->GetBookmarkModel()-> + GetMostRecentlyAddedNodeForURL(tab->GetURL()); + if (node) { + BookmarkDragData bookmark_data(node); + bookmark_data.Write(profile_, data); + } + } + + drag_utils::SetURLAndDragImage(tab->GetURL(), + UTF16ToWideHack(tab->GetTitle()), + tab->GetFavIcon(), + data); + } +} + +int ToolbarView::GetDragOperations(views::View* sender, const gfx::Point& p) { + DCHECK(sender == star_); + TabContents* tab = browser_->GetSelectedTabContents(); + if (!tab || !tab->ShouldDisplayURL() || !tab->GetURL().is_valid()) { + return DragDropTypes::DRAG_NONE; + } + if (profile_ && profile_->GetBookmarkModel() && + profile_->GetBookmarkModel()->IsBookmarked(tab->GetURL())) { + return DragDropTypes::DRAG_MOVE | DragDropTypes::DRAG_COPY | + DragDropTypes::DRAG_LINK; + } + return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK; +} + +//////////////////////////////////////////////////////////////////////////////// // ToolbarView, private: int ToolbarView::PopupTopSpacing() const { @@ -572,6 +675,12 @@ void ToolbarView::CreateLeftSideControls() { forward_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_FORWARD)); forward_->SetID(VIEW_ID_FORWARD_BUTTON); + reload_ = new views::ImageButton(this); + reload_->set_tag(IDC_RELOAD); + reload_->SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_RELOAD)); + reload_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_RELOAD)); + reload_->SetID(VIEW_ID_RELOAD_BUTTON); + home_ = new views::ImageButton(this); home_->set_triggerable_event_flags(views::Event::EF_LEFT_BUTTON_DOWN | views::Event::EF_MIDDLE_BUTTON_DOWN); @@ -584,19 +693,22 @@ void ToolbarView::CreateLeftSideControls() { AddChildView(back_); AddChildView(forward_); + AddChildView(reload_); AddChildView(home_); } void ToolbarView::CreateCenterStack(Profile *profile) { - reload_ = new views::ImageButton(this); - reload_->set_tag(IDC_RELOAD); - reload_->SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_RELOAD)); - reload_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_RELOAD)); - reload_->SetID(VIEW_ID_RELOAD_BUTTON); + star_ = new ToolbarStarToggle(this); + star_->SetDragController(this); + star_->set_profile(profile); + star_->set_host_view(this); + star_->set_bubble_positioner(this); + star_->Init(); location_bar_ = new LocationBarView(profile, browser_->command_updater(), model_, this, - display_mode_ == DISPLAYMODE_LOCATION); + display_mode_ == DISPLAYMODE_LOCATION, + this); // The Go button. go_ = new GoButton(location_bar_, browser_); @@ -605,7 +717,7 @@ void ToolbarView::CreateCenterStack(Profile *profile) { LoadCenterStackImages(); - AddChildView(reload_); + AddChildView(star_); location_bar_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_LOCATION)); AddChildView(location_bar_); location_bar_->Init(); @@ -667,6 +779,15 @@ void ToolbarView::LoadLeftSideControlsImages() { forward_->SetBackground(color, background, tp->GetBitmapNamed(IDR_FORWARD_MASK)); + reload_->SetImage(views::CustomButton::BS_NORMAL, + tp->GetBitmapNamed(IDR_RELOAD)); + reload_->SetImage(views::CustomButton::BS_HOT, + tp->GetBitmapNamed(IDR_RELOAD_H)); + reload_->SetImage(views::CustomButton::BS_PUSHED, + tp->GetBitmapNamed(IDR_RELOAD_P)); + reload_->SetBackground(color, background, + tp->GetBitmapNamed(IDR_BUTTON_MASK)); + home_->SetImage(views::CustomButton::BS_NORMAL, tp->GetBitmapNamed(IDR_HOME)); home_->SetImage(views::CustomButton::BS_HOT, tp->GetBitmapNamed(IDR_HOME_H)); home_->SetImage(views::CustomButton::BS_PUSHED, @@ -676,20 +797,13 @@ void ToolbarView::LoadLeftSideControlsImages() { } void ToolbarView::LoadCenterStackImages() { + star_->LoadImages(); + ThemeProvider* tp = GetThemeProvider(); SkColor color = tp->GetColor(BrowserThemeProvider::COLOR_BUTTON_BACKGROUND); SkBitmap* background = tp->GetBitmapNamed(IDR_THEME_BUTTON_BACKGROUND); - reload_->SetImage(views::CustomButton::BS_NORMAL, - tp->GetBitmapNamed(IDR_RELOAD)); - reload_->SetImage(views::CustomButton::BS_HOT, - tp->GetBitmapNamed(IDR_RELOAD_H)); - reload_->SetImage(views::CustomButton::BS_PUSHED, - tp->GetBitmapNamed(IDR_RELOAD_P)); - reload_->SetBackground(color, background, - tp->GetBitmapNamed(IDR_RELOAD_MASK)); - go_->SetImage(views::CustomButton::BS_NORMAL, tp->GetBitmapNamed(IDR_GO)); go_->SetImage(views::CustomButton::BS_HOT, tp->GetBitmapNamed(IDR_GO_H)); go_->SetImage(views::CustomButton::BS_PUSHED, tp->GetBitmapNamed(IDR_GO_P)); diff --git a/chrome/browser/views/toolbar_view.h b/chrome/browser/views/toolbar_view.h index 6e45799..62faebf 100644 --- a/chrome/browser/views/toolbar_view.h +++ b/chrome/browser/views/toolbar_view.h @@ -11,6 +11,7 @@ #include "base/scoped_ptr.h" #include "chrome/browser/app_menu_model.h" #include "chrome/browser/back_forward_menu_model.h" +#include "chrome/browser/bubble_positioner.h" #include "chrome/browser/command_updater.h" #include "chrome/browser/page_menu_model.h" #include "chrome/browser/pref_member.h" @@ -26,6 +27,7 @@ class BrowserActionsContainer; class Browser; class Profile; +class ToolbarStarToggle; namespace views { class Menu2; @@ -34,12 +36,14 @@ class Menu2; // The Browser Window's toolbar. class ToolbarView : public AccessibleToolbarView, public views::ViewMenuDelegate, + public views::DragController, public views::FocusChangeListener, public menus::SimpleMenuModel::Delegate, public LocationBarView::Delegate, public NotificationObserver, public CommandUpdater::CommandObserver, - public views::ButtonListener { + public views::ButtonListener, + public BubblePositioner { public: explicit ToolbarView(Browser* browser); virtual ~ToolbarView(); @@ -82,6 +86,7 @@ class ToolbarView : public AccessibleToolbarView, // Accessors... Browser* browser() const { return browser_; } BrowserActionsContainer* browser_actions() const { return browser_actions_; } + ToolbarStarToggle* star_button() const { return star_; } GoButton* go_button() const { return go_; } LocationBarView* location_bar() const { return location_bar_; } views::MenuButton* page_menu() const { return page_menu_; } @@ -110,6 +115,9 @@ class ToolbarView : public AccessibleToolbarView, // Overridden from views::BaseButton::ButtonListener: virtual void ButtonPressed(views::Button* sender, const views::Event& event); + // BubblePositioner: + virtual gfx::Rect GetLocationStackBounds() const; + // Overridden from NotificationObserver: virtual void Observe(NotificationType type, const NotificationSource& source, @@ -130,6 +138,17 @@ class ToolbarView : public AccessibleToolbarView, virtual void ThemeChanged(); private: + // Overridden from views::DragController: + virtual void WriteDragData(View* sender, + const gfx::Point& press_pt, + OSExchangeData* data); + virtual int GetDragOperations(View* sender, const gfx::Point& p); + virtual bool CanStartDrag(View* sender, + const gfx::Point& press_pt, + const gfx::Point& p) { + return true; + } + // Returns the number of pixels above the location bar in non-normal display. int PopupTopSpacing() const; @@ -179,8 +198,9 @@ class ToolbarView : public AccessibleToolbarView, // Controls views::ImageButton* back_; views::ImageButton* forward_; - views::ImageButton* home_; views::ImageButton* reload_; + views::ImageButton* home_; + ToolbarStarToggle* star_; LocationBarView* location_bar_; GoButton* go_; BrowserActionsContainer* browser_actions_; diff --git a/chrome/browser/views/url_picker.cc b/chrome/browser/views/url_picker.cc index 3d275d4..5f82832 100644 --- a/chrome/browser/views/url_picker.cc +++ b/chrome/browser/views/url_picker.cc @@ -221,10 +221,10 @@ void UrlPicker::OnSelectionChanged() { if (selection >= 0 && selection < url_table_model_->RowCount()) { std::wstring languages = profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); - // Because the url_field_ is user-editable, we don't strip anything. + // Because the url_field_ is user-editable, we set the URL with + // username:password and escaped path and query. std::wstring formatted = net::FormatUrl(url_table_model_->GetURL(selection), - languages, net::kFormatUrlOmitNothing, UnescapeRule::NONE, NULL, NULL, - NULL); + languages, false, UnescapeRule::NONE, NULL, NULL, NULL); url_field_->SetText(formatted); GetDialogClientView()->UpdateDialogButtons(); } -- cgit v1.1