diff options
author | shess@chromium.org <shess@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-23 20:01:00 +0000 |
---|---|---|
committer | shess@chromium.org <shess@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-23 20:01:00 +0000 |
commit | 69c579e522c4493c15c93ebf33b28a35b1e7213b (patch) | |
tree | 5dde3cc78e0de04bb87613c09be12b47b80d8307 /chrome/browser | |
parent | 12f144239468f206dc82c3f3481fef477f636798 (diff) | |
download | chromium_src-69c579e522c4493c15c93ebf33b28a35b1e7213b.zip chromium_src-69c579e522c4493c15c93ebf33b28a35b1e7213b.tar.gz chromium_src-69c579e522c4493c15c93ebf33b28a35b1e7213b.tar.bz2 |
Re-instate the temporary revert from r45267. That reverted certain
Omnibox, toolbar, tab animations, and other UI changes for purposes of
testing and merging into mstone-5.
Additionally reverts these CLs to fix the earlier revert:
r45271: [Mac] Image references missing from Omnibox revert.
r45268: GTK fix merge failure in uber-revert.
Additional revert which fixed a bug for the branch:
r45381: [Mac] Omnibox popup icons and text lined up under toolbar.
Slight merge conflict which should be good:
r45322: GTK: Implement OnDragCanceled() for autocomplete...
Also ++kThemePackVersion and regenerate the cached theme pak.
Re-instated 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=People go back to complaining about missing http://.
R=pkasting@chromium.org,beng@chromium.org
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45474 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
121 files changed, 4748 insertions, 4918 deletions
diff --git a/chrome/browser/autocomplete/autocomplete.cc b/chrome/browser/autocomplete/autocomplete.cc index 9c7e942..ba37681 100644 --- a/chrome/browser/autocomplete/autocomplete.cc +++ b/chrome/browser/autocomplete/autocomplete.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -27,6 +27,7 @@ #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" @@ -367,6 +368,18 @@ 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, @@ -384,23 +397,40 @@ AutocompleteMatch::AutocompleteMatch(AutocompleteProvider* provider, // static std::string AutocompleteMatch::TypeToString(Type 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"; + 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]; +} - default: - NOTREACHED(); - return std::string(); - } +// 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]; } // static @@ -565,10 +595,14 @@ void AutocompleteProvider::UpdateStarredStateOfMatches() { std::wstring AutocompleteProvider::StringForURLDisplay( const GURL& url, - bool check_accept_lang) const { + bool check_accept_lang, + bool trim_http) const { std::wstring languages = (check_accept_lang && profile_) ? profile_->GetPrefs()->GetString(prefs::kAcceptLanguages) : std::wstring(); - return net::FormatUrl(url, languages); + const net::FormatUrlTypes format_types = trim_http ? + net::kFormatUrlOmitAll : net::kFormatUrlOmitUsernamePassword; + return net::FormatUrl(url, languages, format_types, UnescapeRule::SPACES, + NULL, NULL, NULL); } // AutocompleteResult --------------------------------------------------------- diff --git a/chrome/browser/autocomplete/autocomplete.h b/chrome/browser/autocomplete/autocomplete.h index d64fd6c..54bd9ff 100644 --- a/chrome/browser/autocomplete/autocomplete.h +++ b/chrome/browser/autocomplete/autocomplete.h @@ -314,22 +314,24 @@ struct AutocompleteMatch { // The type of this match. enum Type { - 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. + 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, }; + AutocompleteMatch(); AutocompleteMatch(AutocompleteProvider* provider, int relevance, bool deletable, @@ -338,6 +340,10 @@ 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); @@ -555,7 +561,8 @@ 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) const; + bool check_accept_lang, + bool trim_http) const; // The profile associated with the AutocompleteProvider. Reference is not // owned by us. @@ -776,7 +783,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::URLsForCurrentSelection() moves to the controller. + // AutocompletePopup::InfoForCurrentSelection() 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 new file mode 100644 index 0000000..3e96ff5 --- /dev/null +++ b/chrome/browser/autocomplete/autocomplete_classifier.cc @@ -0,0 +1,34 @@ +// 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 new file mode 100644 index 0000000..3588c27 --- /dev/null +++ b/chrome/browser/autocomplete/autocomplete_classifier.h @@ -0,0 +1,43 @@ +// 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 <string> + +#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<AutocompleteController> 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 f4c2583..9b0aefb 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.cc +++ b/chrome/browser/autocomplete/autocomplete_edit.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -9,6 +9,7 @@ #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" @@ -19,7 +20,6 @@ #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,7 +44,6 @@ 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) { } @@ -81,7 +80,7 @@ const AutocompleteEditModel::State } return State(user_input_in_progress_, user_text_, keyword_, is_keyword_hint_, - keyword_ui_state_, show_search_hint_); + keyword_ui_state_); } void AutocompleteEditModel::RestoreState(const State& state) { @@ -92,7 +91,6 @@ 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); } @@ -122,7 +120,9 @@ void AutocompleteEditModel::SetUserText(const std::wstring& text) { void AutocompleteEditModel::GetDataForURLExport(GURL* url, std::wstring* title, SkBitmap* favicon) { - *url = GetURLForCurrentText(NULL, NULL, NULL); + AutocompleteMatch match; + GetInfoForCurrentText(&match, NULL); + *url = match.destination_url; 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() { +bool AutocompleteEditModel::CurrentTextIsURL() const { // 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,9 +142,15 @@ bool AutocompleteEditModel::CurrentTextIsURL() { if (!user_input_in_progress_) return true; - PageTransition::Type transition = PageTransition::LINK; - GetURLForCurrentText(&transition, NULL, NULL); - return transition == PageTransition::TYPED; + AutocompleteMatch match; + GetInfoForCurrentText(&match, NULL); + return match.transition == PageTransition::TYPED; +} + +AutocompleteMatch::Type AutocompleteEditModel::CurrentTextType() const { + AutocompleteMatch match; + GetInfoForCurrentText(&match, NULL); + return match.type; } bool AutocompleteEditModel::GetURLForText(const std::wstring& text, @@ -174,7 +180,6 @@ 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); @@ -191,14 +196,11 @@ bool AutocompleteEditModel::CanPasteAndGo(const std::wstring& text) const { if (!view_->GetCommandUpdater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL)) return false; - 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_); - + 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; return paste_and_go_url_.is_valid(); } @@ -215,33 +217,30 @@ void AutocompleteEditModel::PasteAndGo() { void AutocompleteEditModel::AcceptInput(WindowOpenDisposition disposition, bool for_drop) { // Get the URL and transition type for the selected entry. - PageTransition::Type transition; - bool is_history_what_you_typed_match; + AutocompleteMatch match; GURL alternate_nav_url; - const GURL url(GetURLForCurrentText(&transition, - &is_history_what_you_typed_match, - &alternate_nav_url)); - if (!url.is_valid()) + GetInfoForCurrentText(&match, &alternate_nav_url); + if (!match.destination_url.is_valid()) return; - if (UTF8ToWide(url.spec()) == permanent_text_) { + if (UTF8ToWide(match.destination_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. - transition = PageTransition::RELOAD; + match.transition = PageTransition::RELOAD; } else if (for_drop || ((paste_state_ != NONE) && - is_history_what_you_typed_match)) { + 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. - transition = PageTransition::LINK; + match.transition = PageTransition::LINK; } - view_->OpenURL(url, disposition, transition, alternate_nav_url, - AutocompletePopupModel::kNoMatch, - is_keyword_hint_ ? std::wstring() : keyword_); + view_->OpenURL(match.destination_url, disposition, match.transition, + alternate_nav_url, AutocompletePopupModel::kNoMatch, + is_keyword_hint_ ? std::wstring() : keyword_); } void AutocompleteEditModel::SendOpenNotification(size_t selected_line, @@ -325,17 +324,20 @@ void AutocompleteEditModel::OnKillFocus() { } bool AutocompleteEditModel::OnEscapeKeyPressed() { - 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 (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 the user wasn't editing, but merely had focus in the edit, allow <esc> @@ -405,35 +407,24 @@ void AutocompleteEditModel::OnUpOrDownKeyPressed(int count) { void AutocompleteEditModel::OnPopupDataChanged( const std::wstring& text, - bool is_temporary_text, + GURL* destination_for_temporary_text_change, const std::wstring& keyword, - 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)); - + bool is_keyword_hint) { // Update keyword/hint-related local state. bool keyword_state_changed = (keyword_ != keyword) || - ((is_keyword_hint_ != is_keyword_hint) && !keyword.empty()) || - (show_search_hint_ != show_search_hint); + ((is_keyword_hint_ != is_keyword_hint) && !keyword.empty()); if (keyword_state_changed) { keyword_ = keyword; is_keyword_hint_ = is_keyword_hint; - show_search_hint_ = show_search_hint; } // Handle changes to temporary text. - if (is_temporary_text) { + if (destination_for_temporary_text_change != NULL) { 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_ = popup_->URLsForCurrentSelection(NULL, NULL, NULL); + original_url_ = *destination_for_temporary_text_change; original_keyword_ui_state_ = keyword_ui_state_; } if (control_key_state_ == DOWN_WITHOUT_CHANGE) { @@ -542,7 +533,6 @@ 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<const AutocompleteResult>(details).ptr(); const AutocompleteResult::const_iterator match(result->default_match()); @@ -559,11 +549,9 @@ 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, false, keyword, is_keyword_hint, - match_type); + OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, is_keyword_hint); } void AutocompleteEditModel::InternalSetUserText(const std::wstring& text) { @@ -586,20 +574,14 @@ std::wstring AutocompleteEditModel::UserTextFromDisplayText( text : (keyword_ + L" " + text); } -GURL AutocompleteEditModel::GetURLForCurrentText( - PageTransition::Type* transition, - bool* is_history_what_you_typed_match, +void AutocompleteEditModel::GetInfoForCurrentText( + AutocompleteMatch* match, GURL* alternate_nav_url) const { if (popup_->IsOpen() || query_in_progress()) { - return popup_->URLsForCurrentSelection(transition, - is_history_what_you_typed_match, - alternate_nav_url); + popup_->InfoForCurrentSelection(match, alternate_nav_url); + } else { + profile_->GetAutocompleteClassifier()->Classify( + UserTextFromDisplayText(view_->GetText()), GetDesiredTLD(), 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 1a0386c..9f4e973 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.h +++ b/chrome/browser/autocomplete/autocomplete_edit.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -83,14 +83,12 @@ class AutocompleteEditModel : public NotificationObserver { const std::wstring& user_text, const std::wstring& keyword, bool is_keyword_hint, - KeywordUIState keyword_ui_state, - bool show_search_hint) + KeywordUIState keyword_ui_state) : 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), - show_search_hint(show_search_hint) { + keyword_ui_state(keyword_ui_state) { } bool user_input_in_progress; @@ -98,7 +96,6 @@ 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, @@ -137,7 +134,10 @@ 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(); + bool CurrentTextIsURL() const; + + // Returns the match type for the current edit contents. + AutocompleteMatch::Type CurrentTextType() const; // 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_ ? has_focus_ : (keyword_ui_state_ != NO_KEYWORD)) ? + return (is_keyword_hint_ || (keyword_ui_state_ != NO_KEYWORD)) ? keyword_ : std::wstring(); } bool is_keyword_hint() const { return is_keyword_hint_; } @@ -220,10 +220,6 @@ 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 @@ -260,21 +256,20 @@ 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 (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). + // |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. // |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, - bool is_temporary_text, + GURL* destination_for_temporary_text_change, const std::wstring& keyword, - bool is_keyword_hint, - AutocompleteMatch::Type type); + bool is_keyword_hint); // Called by the AutocompleteEditView after something changes, with details // about what state changes occured. Updates internal state, updates the @@ -326,16 +321,10 @@ class AutocompleteEditModel : public NotificationObserver { std::wstring DisplayTextFromUserText(const std::wstring& text) const; std::wstring UserTextFromDisplayText(const std::wstring& text) 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; + // 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; AutocompleteEditView* view_; @@ -432,10 +421,6 @@ 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 63c2524..0d4c230 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view.h @@ -59,6 +59,13 @@ 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 86d886d..006395f 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc @@ -17,7 +17,6 @@ #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" @@ -34,9 +33,11 @@ #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 @@ -45,11 +46,13 @@ using gfx::SkColorToGdkColor; namespace { +const gchar* kAutocompleteEditViewGtkKey = "__ACE_VIEW_GTK__"; + const char kTextBaseColor[] = "#808080"; -const char kSecureSchemeColor[] = "#009614"; -const char kInsecureSchemeColor[] = "#c80000"; +const char kSecureSchemeColor[] = "#079500"; +const char kSecurityErrorSchemeColor[] = "#a20000"; -const double kStrikethroughStrokeRed = 210.0 / 256.0; +const double kStrikethroughStrokeRed = 162.0 / 256.0; const double kStrikethroughStrokeWidth = 2.0; size_t GetUTF8Offset(const std::wstring& wide_text, size_t wide_text_offset) { @@ -108,6 +111,26 @@ 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( @@ -116,23 +139,30 @@ AutocompleteEditViewGtk::AutocompleteEditViewGtk( Profile* profile, CommandUpdater* command_updater, bool popup_window_mode, - const BubblePositioner* bubble_positioner) +#if defined(TOOLKIT_VIEWS) + const views::View* location_bar) +#else + GtkWidget* location_bar) +#endif : text_view_(NULL), tag_table_(NULL), text_buffer_(NULL), faded_text_tag_(NULL), secure_scheme_tag_(NULL), - insecure_scheme_tag_(NULL), + security_error_scheme_tag_(NULL), model_(new AutocompleteEditModel(this, controller, profile)), - popup_view_(AutocompletePopupView::CreatePopupView(gfx::Font(), this, - model_.get(), - profile, - bubble_positioner)), +#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 controller_(controller), toolbar_model_(toolbar_model), command_updater_(command_updater), popup_window_mode_(popup_window_mode), - scheme_security_level_(ToolbarModel::NORMAL), + security_level_(ToolbarModel::NONE), mark_set_handler_id_(0), #if defined(OS_CHROMEOS) button_1_pressed_(false), @@ -185,6 +215,7 @@ 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); @@ -215,8 +246,8 @@ void AutocompleteEditViewGtk::Init() { NULL, "foreground", kTextBaseColor, NULL); secure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, NULL, "foreground", kSecureSchemeColor, NULL); - insecure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, - NULL, "foreground", kInsecureSchemeColor, NULL); + security_error_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, + NULL, "foreground", kSecurityErrorSchemeColor, NULL); normal_text_tag_ = gtk_text_buffer_create_tag(text_buffer_, NULL, "foreground", "#000000", NULL); @@ -258,6 +289,8 @@ 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", @@ -284,7 +317,7 @@ void AutocompleteEditViewGtk::Init() { SetBaseColor(); #endif - ViewIDUtil::SetID(widget(), VIEW_ID_AUTOCOMPLETE); + ViewIDUtil::SetID(GetNativeView(), VIEW_ID_AUTOCOMPLETE); } void AutocompleteEditViewGtk::SetFocus() { @@ -318,9 +351,8 @@ 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( @@ -334,15 +366,9 @@ void AutocompleteEditViewGtk::Update(const TabContents* contents) { model_->UpdatePermanentText(toolbar_model_->GetText()); ToolbarModel::SecurityLevel 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(); - } + toolbar_model_->GetSecurityLevel(); + bool changed_security_level = (security_level != security_level_); + security_level_ = security_level; if (contents) { selected_text_.clear(); @@ -392,6 +418,17 @@ 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) { @@ -582,10 +619,8 @@ void AutocompleteEditViewGtk::SetBaseColor() { bool use_gtk = theme_provider_->UseGtkTheme(); #endif - // 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) { + if (use_gtk) { + gtk_widget_modify_cursor(text_view_, NULL, NULL); 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); @@ -600,20 +635,21 @@ 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(is_secure, LocationBarView::BACKGROUND)); - gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, - &background_color); + LocationBarView::GetColor(ToolbarModel::NONE, + LocationBarView::BACKGROUND)); + background_color_ptr = &background_color; #else - gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, - &LocationBarViewGtk::kBackgroundColorByLevel[scheme_security_level_]); + background_color_ptr = &LocationBarViewGtk::kBackgroundColor; #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 @@ -1037,11 +1073,32 @@ 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( @@ -1178,18 +1235,14 @@ 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); @@ -1197,16 +1250,27 @@ void AutocompleteEditViewGtk::HandleCopyOrCutClipboard(GtkWidget* sender) { return; } - // 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; + OwnPrimarySelection(selected_text_); +} - // 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::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_)); + + gtk_target_list_unref(list); + gtk_target_table_free(entries, len); } void AutocompleteEditViewGtk::HandlePasteClipboard(GtkWidget* sender) { @@ -1294,6 +1358,7 @@ 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() { @@ -1305,6 +1370,7 @@ 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() { @@ -1374,22 +1440,21 @@ void AutocompleteEditViewGtk::EmphasizeURLComponents() { strikethrough_ = CharRange(); // Emphasize the scheme for security UI display purposes (if necessary). if (!model_->user_input_in_progress() && scheme.is_nonempty() && - (scheme_security_level_ != ToolbarModel::NORMAL)) { + (security_level_ != ToolbarModel::NONE)) { CharRange scheme_range = CharRange(GetUTF8Offset(text, scheme.begin), GetUTF8Offset(text, scheme.end())); ItersFromCharRange(scheme_range, &start, &end); - if (scheme_security_level_ == ToolbarModel::SECURE) { - gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_, - &start, &end); - } else { + if (security_level_ == ToolbarModel::SECURITY_ERROR) { 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_, insecure_scheme_tag_, + gtk_text_buffer_apply_tag(text_buffer_, security_error_scheme_tag_, &start, &end); + } else { + gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_, &start, &end); } } } @@ -1469,3 +1534,23 @@ 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<AutocompleteEditViewGtk*>( + 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 1eb1736..66b837b 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) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -25,9 +25,11 @@ class AutocompleteEditController; class AutocompleteEditModel; class AutocompletePopupView; -class BubblePositioner; class Profile; class TabContents; +namespace views { +class View; +} #if !defined(TOOLKIT_VIEWS) class GtkThemeProvider; @@ -53,14 +55,16 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, Profile* profile, CommandUpdater* command_updater, bool popup_window_mode, - const BubblePositioner* bubble_positioner); +#if defined(TOOLKIT_VIEWS) + const views::View* location_bar); +#else + GtkWidget* location_bar); +#endif ~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(); @@ -82,6 +86,9 @@ 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); } @@ -134,6 +141,9 @@ 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, @@ -172,6 +182,20 @@ 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); @@ -209,7 +233,8 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, // Internally invoked whenever the text changes in some way. void TextChanged(); - // Save |selected_text| as the PRIMARY X selection. + // Save |selected_text| as the PRIMARY X selection. Unlike + // OwnPrimarySelection(), this won't set an owner or use callbacks. void SavePrimarySelection(const std::string& selected_text); // Update the field with |text| and set the selection. @@ -239,7 +264,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, GtkTextBuffer* text_buffer_; GtkTextTag* faded_text_tag_; GtkTextTag* secure_scheme_tag_; - GtkTextTag* insecure_scheme_tag_; + GtkTextTag* security_error_scheme_tag_; GtkTextTag* normal_text_tag_; scoped_ptr<AutocompleteEditModel> model_; @@ -255,7 +280,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, // different presentation (smaller font size). This is used for popups. bool popup_window_mode_; - ToolbarModel::SecurityLevel scheme_security_level_; + ToolbarModel::SecurityLevel security_level_; // Selection at the point where the user started using the // arrows to move around in the popup. @@ -272,8 +297,12 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, // it, we pass this string to SavePrimarySelection()). std::string selected_text_; - // ID of the signal handler for "mark-set" on |text_buffer_|. + // 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_|. 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 4cf7aee..740fde7 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h @@ -13,7 +13,6 @@ class AutocompleteEditController; class AutocompletePopupViewMac; -class BubblePositioner; class Clipboard; class Profile; class ToolbarModel; @@ -24,7 +23,6 @@ class AutocompleteEditViewMac : public AutocompleteEditView, public AutocompleteTextFieldObserver { public: AutocompleteEditViewMac(AutocompleteEditController* controller, - const BubblePositioner* bubble_positioner, ToolbarModel* toolbar_model, Profile* profile, CommandUpdater* command_updater, @@ -48,6 +46,10 @@ 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); } @@ -98,6 +100,10 @@ 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 e337744..a4a54ce 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm +++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm @@ -9,6 +9,7 @@ #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" @@ -20,6 +21,7 @@ #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. @@ -61,15 +63,6 @@ const NSColor* ColorWithRGBBytes(int rr, int gg, int bb) { blue:static_cast<float>(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]; @@ -77,11 +70,14 @@ const NSColor* HostTextColor() { const NSColor* BaseTextColor() { return [NSColor darkGrayColor]; } +const NSColor* EVSecureSchemeColor() { + return ColorWithRGBBytes(0x07, 0x95, 0x00); +} const NSColor* SecureSchemeColor() { - return ColorWithRGBBytes(0x00, 0x96, 0x14); + return ColorWithRGBBytes(0x00, 0x0e, 0x95); } -const NSColor* InsecureSchemeColor() { - return ColorWithRGBBytes(0xc8, 0x00, 0x00); +const NSColor* SecurityErrorSchemeColor() { + return ColorWithRGBBytes(0xa2, 0x00, 0x00); } // Store's the model and view state across tab switches. @@ -125,20 +121,57 @@ 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(), bubble_positioner, profile, field)), + popup_view_(new AutocompletePopupViewMac(this, model_.get(), profile, + field)), controller_(controller), toolbar_model_(toolbar_model), command_updater_(command_updater), @@ -272,6 +305,17 @@ 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) { @@ -410,32 +454,23 @@ 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 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; - } + const ToolbarModel::SecurityLevel security_level = + toolbar_model_->GetSecurityLevel(); // Emphasize the scheme for security UI display purposes (if necessary). if (!model_->user_input_in_progress() && scheme.is_nonempty() && - (scheme_security_level != ToolbarModel::NORMAL)) { + (security_level != ToolbarModel::NONE)) { NSColor* color; - if (scheme_security_level == ToolbarModel::SECURE) { - color = SecureSchemeColor(); - } else { - color = InsecureSchemeColor(); + if (security_level == ToolbarModel::EV_SECURE) { + color = EVSecureSchemeColor(); + } else if (security_level == ToolbarModel::SECURITY_ERROR) { + color = SecurityErrorSchemeColor(); // 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 6ead1fe..5a0632f 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc @@ -28,7 +28,6 @@ #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" @@ -387,10 +386,10 @@ AutocompleteEditViewWin::AutocompleteEditViewWin( Profile* profile, CommandUpdater* command_updater, bool popup_window_mode, - const BubblePositioner* bubble_positioner) + const views::View* location_bar) : model_(new AutocompleteEditModel(this, controller, profile)), - popup_view_(AutocompletePopupView::CreatePopupView( - font, this, model_.get(), profile, bubble_positioner)), + popup_view_(new AutocompletePopupContentsView(font, this, model_.get(), + profile, location_bar)), controller_(controller), parent_view_(parent_view), toolbar_model_(toolbar_model), @@ -407,8 +406,9 @@ AutocompleteEditViewWin::AutocompleteEditViewWin( in_drag_(false), initiated_drag_(false), drop_highlight_position_(-1), - background_color_(0), - scheme_security_level_(ToolbarModel::NORMAL), + background_color_(skia::SkColorToCOLORREF(LocationBarView::GetColor( + ToolbarModel::NONE, LocationBarView::BACKGROUND))), + security_level_(ToolbarModel::NONE), 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,6 +459,8 @@ 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); @@ -508,30 +510,21 @@ void AutocompleteEditViewWin::Update( model_->UpdatePermanentText(toolbar_model_->GetText()); const ToolbarModel::SecurityLevel 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_); + toolbar_model_->GetSecurityLevel(); + const bool changed_security_level = (security_level != security_level_); // Bail early when no visible state will actually change (prevents an // unnecessary ScopedFreeze, and thus UpdateWindow()). - if ((background_color == background_color_) && !changed_security_level && - !visibly_changed_permanent_text && !tab_for_state_restoring) + if (!changed_security_level && !visibly_changed_permanent_text && + !tab_for_state_restoring) return; - // 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; + // 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; // 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 @@ -605,6 +598,16 @@ 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) { @@ -1369,15 +1372,6 @@ void AutocompleteEditViewWin::OnKillFocus(HWND focus_wnd) { ScopedFreeze freeze(this, GetTextObjectModel()); DefWindowProc(WM_KILLFOCUS, reinterpret_cast<WPARAM>(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, @@ -1687,12 +1681,6 @@ 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_); @@ -2060,11 +2048,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(is_secure, + cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor( + security_level_, 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 @@ -2075,7 +2063,7 @@ void AutocompleteEditViewWin::EmphasizeURLComponents() { if (emphasize) { // We've found a host name, give it more emphasis. cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor( - is_secure, LocationBarView::TEXT)); + security_level_, LocationBarView::TEXT)); SetSelection(host.begin, host.end()); SetSelectionCharFormat(cf); } @@ -2083,13 +2071,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() && - (scheme_security_level_ != ToolbarModel::NORMAL)) { - if (!is_secure) { + (security_level_ != ToolbarModel::NONE)) { + if (security_level_ == ToolbarModel::SECURITY_ERROR) { insecure_scheme_component_.begin = scheme.begin; insecure_scheme_component_.len = scheme.len; } cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor( - is_secure, LocationBarView::SECURITY_TEXT)); + security_level_, LocationBarView::SECURITY_TEXT)); SetSelection(scheme.begin, scheme.end()); SetSelectionCharFormat(cf); } @@ -2183,8 +2171,8 @@ void AutocompleteEditViewWin::DrawSlashForInsecureScheme( canvas.save(); if (selection_rect.isEmpty() || canvas.clipRect(selection_rect, SkRegion::kDifference_Op)) { - paint.setColor(LocationBarView::GetColor(false, - LocationBarView::SCHEME_STRIKEOUT)); + paint.setColor(LocationBarView::GetColor(security_level_, + LocationBarView::SECURITY_TEXT)); canvas.drawLine(start_point.fX, start_point.fY, end_point.fX, end_point.fY, paint); } @@ -2192,7 +2180,7 @@ void AutocompleteEditViewWin::DrawSlashForInsecureScheme( // Draw the selected portion of the stroke. if (!selection_rect.isEmpty() && canvas.clipRect(selection_rect)) { - paint.setColor(LocationBarView::GetColor(false, + paint.setColor(LocationBarView::GetColor(security_level_, 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 9de2d34..33af6a7 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 BubblePositioner* bubble_positioner); + const views::View* location_bar); ~AutocompleteEditViewWin(); views::View* parent_view() const { return parent_view_; } @@ -91,6 +91,9 @@ 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); } @@ -476,7 +479,7 @@ class AutocompleteEditViewWin // Security UI-related data. COLORREF background_color_; - ToolbarModel::SecurityLevel scheme_security_level_; + ToolbarModel::SecurityLevel 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 41e0255..009cc0b 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_model.cc +++ b/chrome/browser/autocomplete/autocomplete_popup_model.cc @@ -103,12 +103,24 @@ 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) && @@ -116,27 +128,15 @@ void AutocompletePopupModel::SetSelectedLine(size_t line, inline_autocomplete_text = match.fill_into_edit.substr(match.inline_autocomplete_offset); } - edit_model_->OnPopupDataChanged(inline_autocomplete_text, false, - keyword, is_keyword_hint, match.type); + edit_model_->OnPopupDataChanged(inline_autocomplete_text, NULL, + keyword, is_keyword_hint); } else { - edit_model_->OnPopupDataChanged(match.fill_into_edit, true, - keyword, is_keyword_hint, match.type); + edit_model_->OnPopupDataChanged(match.fill_into_edit, ¤t_destination, + keyword, is_keyword_hint); } // Repaint old and new selected lines immediately, so that the edit doesn't - // 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_); + // appear to update [much] faster than the popup. view_->PaintUpdatesNow(); } @@ -147,22 +147,21 @@ void AutocompletePopupModel::ResetToDefaultMatch() { view_->OnDragCanceled(); } -GURL AutocompletePopupModel::URLsForCurrentSelection( - PageTransition::Type* transition, - bool* is_history_what_you_typed_match, +void AutocompletePopupModel::InfoForCurrentSelection( + AutocompleteMatch* 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 GURL(); + return; // 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 @@ -177,15 +176,10 @@ GURL AutocompletePopupModel::URLsForCurrentSelection( // called instead. CHECK(!result->empty()); CHECK(selected_line_ < result->size()); - match = result->begin() + selected_line_; + *match = result->match_at(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, @@ -239,7 +233,7 @@ void AutocompletePopupModel::Move(int count) { } void AutocompletePopupModel::TryDeletingCurrentItem() { - // We could use URLsForCurrentSelection() here, but it seems better to try + // We could use InfoForCurrentSelection() 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 166a238..a986419 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_model.h +++ b/chrome/browser/autocomplete/autocomplete_popup_model.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -73,15 +73,9 @@ class AutocompletePopupModel : public NotificationObserver { // will change the selected line back to the default match and redraw. void ResetToDefaultMatch(); - // 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. + // 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|. // // 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 @@ -89,10 +83,8 @@ class AutocompletePopupModel : public NotificationObserver { // // TODO(pkasting): When manually_selected_match_ moves to the controller, this // can move too. - GURL URLsForCurrentSelection( - PageTransition::Type* transition, - bool* is_history_what_you_typed_match, - GURL* alternate_nav_url) const; + void InfoForCurrentSelection(AutocompleteMatch* 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 41b21a6..5674e4b 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_view.h +++ b/chrome/browser/autocomplete/autocomplete_popup_view.h @@ -13,15 +13,7 @@ #include "build/build_config.h" -class AutocompleteEditView; class AutocompletePopupModel; -class BubblePositioner; -namespace gfx { -class Font; -} -class AutocompleteEditViewWin; -class AutocompleteEditModel; -class Profile; class AutocompletePopupView { public: @@ -48,17 +40,6 @@ 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 0332c28..2f9895d 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) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -18,16 +18,18 @@ #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 { @@ -44,27 +46,40 @@ 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 = 16; +const int kIconWidth = 17; + // We want to vertically center the image in the result space. -const int kIconTopPadding = 4; +const int kIconTopPadding = 2; + // Space between the left edge (including the border) and the text. -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; +const int kIconLeftPadding = 5 + kBorderThickness; + +// Space between the image and the text. +const int kIconRightPadding = 7; + // 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"; @@ -103,6 +118,7 @@ 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 @@ -139,7 +155,7 @@ void SetupLayoutForMatch(PangoLayout* layout, // support it. const GdkColor* color = base_color; if (i->style & ACMatchClassification::URL) { - color = &kURLTextColor; + color = url_color; // Insert a left to right embedding to make sure that URLs are shown LTR. std::string lre(kLRE); text_utf8.insert(offset, lre); @@ -164,48 +180,81 @@ void SetupLayoutForMatch(PangoLayout* layout, pango_attr_list_unref(attrs); } -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). - 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; +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; + } } - return NULL; + // 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)); +} + +// 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)); } } // namespace @@ -214,12 +263,13 @@ AutocompletePopupViewGtk::AutocompletePopupViewGtk( AutocompleteEditView* edit_view, AutocompleteEditModel* edit_model, Profile* profile, - const BubblePositioner* bubble_positioner) + GtkWidget* location_bar) : model_(new AutocompletePopupModel(this, edit_model, profile)), edit_view_(edit_view), - bubble_positioner_(bubble_positioner), + location_bar_(location_bar), window_(gtk_window_new(GTK_WINDOW_POPUP)), layout_(NULL), + theme_provider_(GtkThemeProvider::GetFrom(profile)), ignore_mouse_drag_(false), opened_(false) { GTK_WIDGET_UNSET_FLAGS(window_, GTK_CAN_FOCUS); @@ -229,8 +279,6 @@ 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 @@ -263,6 +311,11 @@ 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 @@ -317,16 +370,85 @@ 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) { - 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; + 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; } void AutocompletePopupViewGtk::Hide() { @@ -426,7 +548,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, &kBorderColor); + gdk_gc_set_rgb_fg_color(gc, &border_color_); // 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 @@ -439,8 +561,17 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget, pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE); - // TODO(deanm): Intersect the line and damage rects, and only repaint and - // layout the lines that are actually damaged. For now paint everything. + // 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; + for (size_t i = 0; i < result.size(); ++i) { gfx::Rect line_rect = GetRectForLine(i, window_rect.width()); // Only repaint and layout damaged lines. @@ -451,18 +582,19 @@ 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 ? &kSelectedBackgroundColor : - &kHoveredBackgroundColor); + gdk_gc_set_rgb_fg_color(gc, is_selected ? &selected_background_color_ : + &hovered_background_color_); // 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 : - line_rect.width() - kIconLeftPadding - kIconWidth; + int icon_start_x = ltr ? (kIconLeftPadding - gtk_offset) : + (line_rect.width() - kIconLeftPadding - kIconWidth + gtk_offset); // Draw the icon for this result. - DrawFullPixbuf(drawable, gc, IconForMatch(match, is_selected), + DrawFullPixbuf(drawable, gc, + IconForMatch(theme_provider_, match, is_selected), icon_start_x, line_rect.y() + kIconTopPadding); // Draw the results text vertically centered in the results space. @@ -476,7 +608,11 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget, // Note: We force to URL to LTR for all text directions. SetupLayoutForMatch(layout_, match.contents, match.contents_class, - &kContentTextColor, std::string()); + is_selected ? &selected_content_text_color_ : + &content_text_color_, + is_selected ? &url_selected_text_color_ : + &url_text_color_, + std::string()); int actual_content_width, actual_content_height; pango_layout_get_size(layout_, @@ -490,22 +626,25 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget, line_rect.y() + ((kHeightPerResult - actual_content_height) / 2)); gdk_draw_layout(drawable, gc, - ltr ? kIconAreaWidth : text_width - actual_content_width, + ltr ? (kIconAreaWidth - gtk_offset) : + (text_width - actual_content_width + gtk_offset), 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 ? &kDescriptionSelectedTextColor : - &kDescriptionTextColor, + is_selected ? &description_selected_text_color_ : + &description_text_color_, + is_selected ? &url_selected_text_color_ : + &url_text_color_, std::string(" - ")); gint actual_description_width; pango_layout_get_size(layout_, &actual_description_width, NULL); - gdk_draw_layout(drawable, gc, - ltr ? kIconAreaWidth + actual_content_width : - text_width - actual_content_width - - actual_description_width / PANGO_SCALE, + gdk_draw_layout(drawable, gc, ltr ? + (kIconAreaWidth - gtk_offset + actual_content_width) : + (text_width - actual_content_width + gtk_offset - + (actual_description_width / PANGO_SCALE)), content_y, layout_); } } @@ -514,14 +653,3 @@ 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 a56a55a..4759417 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) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -10,23 +10,27 @@ #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 { +class AutocompletePopupViewGtk : public AutocompletePopupView, + public NotificationObserver { public: AutocompletePopupViewGtk(AutocompleteEditView* edit_view, AutocompleteEditModel* edit_model, Profile* profile, - const BubblePositioner* bubble_positioner); + GtkWidget* location_bar); ~AutocompletePopupViewGtk(); - // Implement the AutocompletePopupView interface. + // Overridden from AutocompletePopupView: virtual bool IsOpen() const { return opened_; } virtual void InvalidateLine(size_t line); virtual void UpdatePopupAppearance(); @@ -34,6 +38,11 @@ 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(); @@ -79,7 +88,7 @@ class AutocompletePopupViewGtk : public AutocompletePopupView { scoped_ptr<AutocompletePopupModel> model_; AutocompleteEditView* edit_view_; - const BubblePositioner* bubble_positioner_; + GtkWidget* location_bar_; // 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. @@ -87,6 +96,22 @@ 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_; + // If the user cancels a dragging action (i.e. by pressing ESC), we don't have // a convenient way to release mouse capture. Instead we use this flag to // simply ignore all remaining drag events, and the eventual mouse release diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_mac.h b/chrome/browser/autocomplete/autocomplete_popup_view_mac.h index a430f58..56d20fd 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) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -32,7 +32,6 @@ class AutocompletePopupViewMac : public AutocompletePopupView { public: AutocompletePopupViewMac(AutocompleteEditViewMac* edit_view, AutocompleteEditModel* edit_model, - const BubblePositioner* bubble_positioner, Profile* profile, NSTextField* field); virtual ~AutocompletePopupViewMac(); @@ -109,7 +108,6 @@ class AutocompletePopupViewMac : public AutocompletePopupView { scoped_ptr<AutocompletePopupModel> 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 2ab01ad..29ea9ab 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) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -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 = 2.0; +const CGFloat kPopupFieldGap = 0.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 = 6.0; +const CGFloat kLeftRightMargin = 5.0; // How far to offset the text column from the left. -const CGFloat kTextXOffset = 31.0; +const CGFloat kTextXOffset = 29.0; // Animation duration when animating the popup window smaller. const CGFloat kShrinkAnimationDuration = 0.1; @@ -78,54 +78,6 @@ 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 @@ -293,12 +245,10 @@ 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); @@ -365,8 +315,12 @@ void AutocompletePopupViewMac::UpdatePopupAppearance() { CreatePopupIfNeeded(); // Layout the popup and size it to land underneath the field. - NSRect r = - NSRectFromCGRect(bubble_positioner_->GetLocationStackBounds().ToCGRect()); + // 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); r.origin = [[field_ window] convertBaseToScreen:r.origin]; DCHECK_GT(r.size.width, 0.0); @@ -386,7 +340,9 @@ 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); - [cell setImage:MatchIcon(match)]; + const int resource_id = match.starred ? IDR_OMNIBOX_STAR + : AutocompleteMatch::TypeToIcon(match.type); + [cell setImage:AutocompleteEditViewMac::ImageForResource(resource_id)]; [cell setAttributedTitle:MatchText(match, resultFont, r.size.width)]; } @@ -507,7 +463,11 @@ void AutocompletePopupViewMac::OpenURLForRow(int row, bool force_background) { imageRect.origin.y += floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2); imageRect.origin.x += kLeftRightMargin; - [self drawImage:image withFrame:imageRect inView:controlView]; + [image setFlipped:[controlView isFlipped]]; + [image drawInRect:imageRect + fromRect:NSZeroRect // Entire image + operation:NSCompositeSourceOver + fraction:1.0]; } // Adjust the title position to be lined up under the field's text. @@ -704,10 +664,15 @@ 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 bezierPathWithRoundedRect:[self bounds] - xRadius:kPopupRoundingRadius - yRadius:kPopupRoundingRadius]; + [NSBezierPath gtm_bezierPathWithRoundRect:[self bounds] + topLeftCornerRadius:kPopupRoundingRadius + topRightCornerRadius:kPopupRoundingRadius + bottomLeftCornerRadius:0.0 + bottomRightCornerRadius:0.0]; // 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 ac81c31..1e72ceb 100644 --- a/chrome/browser/autocomplete/history_contents_provider.cc +++ b/chrome/browser/autocomplete/history_contents_provider.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -207,11 +207,9 @@ 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); + match.fill_into_edit = StringForURLDisplay(result.url(), true, trim_http_); 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 2708d47..a748700 100644 --- a/chrome/browser/autocomplete/history_url_provider.cc +++ b/chrome/browser/autocomplete/history_url_provider.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -256,10 +256,14 @@ AutocompleteMatch HistoryURLProvider::SuggestExactInput( const GURL& url = input.canonicalized_url(); if (url.is_valid()) { match.destination_url = url; - match.fill_into_edit = StringForURLDisplay(url, false); + match.fill_into_edit = StringForURLDisplay(url, false, 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 @@ -828,17 +832,13 @@ 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, 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; - } - } + match_type == WHAT_YOU_TYPED ? std::wstring() : params->languages, + format_types, UnescapeRule::SPACES, NULL, NULL, + &inline_autocomplete_offset); if (!params->input.prevent_inline_autocomplete()) match.inline_autocomplete_offset = inline_autocomplete_offset; DCHECK((match.inline_autocomplete_offset == std::wstring::npos) || @@ -846,15 +846,8 @@ 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, 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; - } - } + match_type == WHAT_YOU_TYPED ? std::wstring() : params->languages, + format_types, UnescapeRule::SPACES, NULL, NULL, &match_start); 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 5833611..acba81e 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(this, 0, false, - AutocompleteMatch::SEARCH_WHAT_YOU_TYPED); + AutocompleteMatch match; + match.provider = this; match.contents.assign(l10n_util::GetString(IDS_EMPTY_KEYWORD_VALUE)); match.contents_class.push_back( ACMatchClassification(0, ACMatchClassification::NONE)); @@ -737,10 +737,9 @@ AutocompleteMatch SearchProvider::NavigationToMatch( AutocompleteMatch match(this, relevance, false, AutocompleteMatch::NAVSUGGEST); match.destination_url = navigation.url; - match.contents = StringForURLDisplay(navigation.url, true); - if (!url_util::FindAndCompareScheme(WideToUTF8(input_text), - chrome::kHttpScheme, NULL)) - TrimHttpPrefix(&match.contents); + const bool trim_http = !url_util::FindAndCompareScheme( + WideToUTF8(input_text), chrome::kHttpScheme, NULL); + match.contents = StringForURLDisplay(navigation.url, true, trim_http); 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 f7848e4..0ac5416 100644 --- a/chrome/browser/bookmarks/bookmark_table_model.cc +++ b/chrome/browser/bookmarks/bookmark_table_model.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -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, false, - UnescapeRule::SPACES, NULL, NULL, NULL); + std::wstring url_text = net::FormatUrl(node->GetURL(), languages, + net::kFormatUrlOmitAll, 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 2214e4c..4ffeeb2 100644 --- a/chrome/browser/bookmarks/bookmark_utils.cc +++ b/chrome/browser/bookmarks/bookmark_utils.cc @@ -224,7 +224,8 @@ bool DoesBookmarkContainWords(const BookmarkNode* node, DoesBookmarkTextContainWords( l10n_util::ToLower(UTF8ToWide(node->GetURL().spec())), words) || DoesBookmarkTextContainWords(l10n_util::ToLower(net::FormatUrl( - node->GetURL(), languages, false, true, NULL, NULL, NULL)), words); + node->GetURL(), languages, net::kFormatUrlOmitNothing, + UnescapeRule::NORMAL, NULL, NULL, NULL)), words); } } // namespace diff --git a/chrome/browser/browser_theme_pack.cc b/chrome/browser/browser_theme_pack.cc index d0252f1..3159bf7 100644 --- a/chrome/browser/browser_theme_pack.cc +++ b/chrome/browser/browser_theme_pack.cc @@ -4,37 +4,26 @@ #include "chrome/browser/browser_theme_pack.h" -#include <algorithm> -#include <climits> -#include <set> -#include <vector> - #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 = 7; +const int kThemePackVersion = 8; // 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 @@ -131,42 +120,33 @@ PersistingImagesTable kPersistingImages[] = { { 21, IDR_FORWARD_H, NULL }, { 22, IDR_FORWARD_P, NULL }, { 23, IDR_RELOAD, 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 } + { 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 } }; int GetPersistentIDByName(const std::string& key) { @@ -516,6 +496,8 @@ 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); @@ -965,6 +947,7 @@ void BrowserThemePack::GenerateTintedButtons( for (std::set<int>::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<SkBitmap> button(new SkBitmap(*rb.GetBitmapNamed(*it))); diff --git a/chrome/browser/browser_theme_provider.cc b/chrome/browser/browser_theme_provider.cc index d682548..92fefc3 100644 --- a/chrome/browser/browser_theme_provider.cc +++ b/chrome/browser/browser_theme_provider.cc @@ -1,40 +1,21 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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/browser_theme_provider.h" #include "app/resource_bundle.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 "base/utf_string_conversions.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" @@ -62,15 +43,15 @@ SkColor TintForUnderline(SkColor input) { } // Default colors. -const SkColor kDefaultColorFrame = SkColorSetRGB(77, 139, 217); -const SkColor kDefaultColorFrameInactive = SkColorSetRGB(152, 188, 233); +const SkColor kDefaultColorFrame = SkColorSetRGB(66, 116, 201); +const SkColor kDefaultColorFrameInactive = SkColorSetRGB(161, 182, 228); 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(210, 225, 246); +const SkColor kDefaultColorToolbar = SkColorSetRGB(223, 223, 223); #endif const SkColor kDefaultColorTabText = SK_ColorBLACK; #if defined(OS_MACOSX) @@ -154,15 +135,16 @@ 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_H, IDR_RELOAD_P, + IDR_RELOAD, IDR_RELOAD_NOBORDER, IDR_RELOAD_NOBORDER_CENTER, 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 deleted file mode 100644 index 7ea4df0..0000000 --- a/chrome/browser/bubble_positioner.h +++ /dev/null @@ -1,24 +0,0 @@ -// 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 4d804ca..89c5ffe 100644 --- a/chrome/browser/cert_store.cc +++ b/chrome/browser/cert_store.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -88,7 +88,8 @@ bool CertStore::RetrieveCert(int cert_id, CertMap::iterator iter = id_to_cert_.find(cert_id); if (iter == id_to_cert_.end()) return false; - *cert = iter->second; + if (cert) + *cert = iter->second; return true; } diff --git a/chrome/browser/cert_store.h b/chrome/browser/cert_store.h index 995a3db..0b19540 100644 --- a/chrome/browser/cert_store.h +++ b/chrome/browser/cert_store.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -34,9 +34,9 @@ class CertStore : public NotificationObserver { // Note: ids starts at 1. int StoreCert(net::X509Certificate* cert, int render_process_host_id); - // 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. + // 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. bool RetrieveCert(int cert_id, scoped_refptr<net::X509Certificate>* cert); // NotificationObserver implementation. diff --git a/chrome/browser/chromeos/compact_location_bar_host.cc b/chrome/browser/chromeos/compact_location_bar_host.cc index 1806421..4bdbc44 100644 --- a/chrome/browser/chromeos/compact_location_bar_host.cc +++ b/chrome/browser/chromeos/compact_location_bar_host.cc @@ -22,7 +22,6 @@ #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" @@ -270,10 +269,6 @@ 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 5b59afa..b1f4d83 100644 --- a/chrome/browser/chromeos/compact_location_bar_host.h +++ b/chrome/browser/chromeos/compact_location_bar_host.h @@ -16,7 +16,6 @@ class BrowserView; class TabContents; class Tab; -class ToolbarStarToggle; namespace chromeos { @@ -61,9 +60,6 @@ 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 93a7d2b..cfffec2 100644 --- a/chrome/browser/chromeos/compact_location_bar_view.cc +++ b/chrome/browser/chromeos/compact_location_bar_view.cc @@ -8,10 +8,8 @@ #include <algorithm> #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" @@ -24,7 +22,6 @@ #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" @@ -33,12 +30,10 @@ #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; @@ -51,8 +46,7 @@ const int kWidgetsSeparatorWidth = 2; CompactLocationBarView::CompactLocationBarView(CompactLocationBarHost* host) : DropdownBarView(host), reload_(NULL), - browser_actions_(NULL), - star_(NULL) { + browser_actions_(NULL) { SetFocusable(true); } @@ -102,7 +96,7 @@ void CompactLocationBarView::Init() { reload_->SetImage(views::CustomButton::BS_PUSHED, tp->GetBitmapNamed(IDR_RELOAD_P)); reload_->SetBackground(color, background, - tp->GetBitmapNamed(IDR_BUTTON_MASK)); + tp->GetBitmapNamed(IDR_RELOAD_MASK)); AddChildView(reload_); @@ -121,14 +115,6 @@ 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 @@ -146,15 +132,12 @@ 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 = - reload_size.width() + kEntryLeftMargin + star_size.width() + + int width = kCompactLocationLeftMargin + reload_size.width() + std::max(kDefaultLocationEntryWidth, location_entry_view_->GetPreferredSize().width()) + ba_size.width() + - kCompactLocationLeftMargin + kCompactLocationRightMargin; return gfx::Size(width, kDefaultLocationBarHeight); } @@ -169,12 +152,7 @@ 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() + 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(); + cur_x += reload_size.width(); gfx::Size ba_size = browser_actions_->GetPreferredSize(); int ba_y = (height() - ba_size.height()) / 2; @@ -268,62 +246,4 @@ 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 889a630..a3c750f 100644 --- a/chrome/browser/chromeos/compact_location_bar_view.h +++ b/chrome/browser/chromeos/compact_location_bar_view.h @@ -6,7 +6,6 @@ #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" @@ -17,11 +16,9 @@ class AutocompleteEditViewGtk; class Browser; class BrowserActionsContainer; class BrowserView; -class ToolbarStarToggleGtk; class Tab; class TabContents; class TabStrip; -class ToolbarStarToggle; namespace views { class ImageButton; @@ -35,9 +32,7 @@ namespace chromeos { // navigation bar mode. class CompactLocationBarView : public DropdownBarView, public views::ButtonListener, - public AutocompleteEditController, - public BubblePositioner, - public views::DragController { + public AutocompleteEditController { public: explicit CompactLocationBarView(CompactLocationBarHost* host); ~CompactLocationBarView(); @@ -47,8 +42,6 @@ class CompactLocationBarView : public DropdownBarView, void Update(const TabContents* contents); - ToolbarStarToggle* star_button() const { return star_; } - private: Browser* browser() const; @@ -81,20 +74,6 @@ 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<CompactLocationBarHost*>(host()); } @@ -103,7 +82,6 @@ class CompactLocationBarView : public DropdownBarView, scoped_ptr<AutocompleteEditViewGtk> 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 bf2dac7..d6aff2f 100644 --- a/chrome/browser/chromeos/frame/browser_view.cc +++ b/chrome/browser/chromeos/frame/browser_view.cc @@ -28,7 +28,6 @@ #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,19 +439,6 @@ 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) { @@ -463,7 +449,7 @@ void BrowserView::ButtonPressed(views::Button* sender, origin.Offset(kAppLauncherLeftPadding, 0); views::RootView::ConvertPointToScreen(this, &origin); bounds.set_origin(origin); - ::AppLauncher::Show(browser(), bounds); + ::AppLauncher::Show(browser(), bounds, gfx::Point()); } // views::ContextMenuController overrides. diff --git a/chrome/browser/chromeos/frame/browser_view.h b/chrome/browser/chromeos/frame/browser_view.h index 3bdea4f..647211f 100644 --- a/chrome/browser/chromeos/frame/browser_view.h +++ b/chrome/browser/chromeos/frame/browser_view.h @@ -66,8 +66,6 @@ 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 1b1856d..8e16705 100644 --- a/chrome/browser/cocoa/autocomplete_text_field.h +++ b/chrome/browser/cocoa/autocomplete_text_field.h @@ -119,6 +119,13 @@ 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 60d3507..a07cac1 100644 --- a/chrome/browser/cocoa/autocomplete_text_field.mm +++ b/chrome/browser/cocoa/autocomplete_text_field.mm @@ -124,14 +124,10 @@ 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; - } + // Give the cell a chance to intercept clicks in page-actions and + // other decorative items. + if ([cell mouseDown:theEvent inRect:bounds ofView:self]) { + return; } NSText* editor = [self currentEditor]; @@ -199,6 +195,7 @@ // 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]]; @@ -206,8 +203,17 @@ 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. @@ -371,4 +377,13 @@ 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 1e0a3c5..bc791cf 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_cell.h +++ b/chrome/browser/cocoa/autocomplete_text_field_cell.h @@ -13,7 +13,15 @@ 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_; @@ -21,12 +29,20 @@ 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 @@ -44,10 +60,17 @@ class ExtensionAction; // side of the field. Exclusive WRT |keywordString_|; scoped_nsobject<NSAttributedString> hintString_; - // 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_; + // 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_; // List of views showing visible Page Actions. Owned by the location bar. // Display is exclusive WRT the |hintString_| and |keywordString_|. @@ -77,34 +100,58 @@ class ExtensionAction; availableWidth:(CGFloat)width; - (void)clearKeywordAndHint; -- (void)setSecurityImageView:(LocationBarViewMac::SecurityImageView*)view; +- (void)setLocationIconView:(LocationBarViewMac::LocationIconView*)view; +- (void)setStarIconView:(LocationBarViewMac::LocationBarImageView*)view; +- (void)setSecurityLabelView:(LocationBarViewMac::LocationBarImageView*)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; -// 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; +// Find the icon under the event. |nil| if |theEvent| is not over +// anything. +- (AutocompleteTextFieldIcon*)iconForEvent:(NSEvent*)theEvent + inRect:(NSRect)cellFrame + ofView:(AutocompleteTextField*)controlView; // 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*)event +- (NSMenu*)actionMenuForEvent:(NSEvent*)theEvent inRect:(NSRect)cellFrame - ofView:(NSView*)aView; + 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; @end @@ -118,8 +165,4 @@ 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 7b7f35c..9801892 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_cell.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_cell.mm @@ -7,6 +7,20 @@ #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 { @@ -35,16 +49,28 @@ 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 = 5; +const NSInteger kIconLabelYOffset = 7; // 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); @@ -54,20 +80,103 @@ 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<AutocompleteTextAttachmentCell> attachmentCell( + [[AutocompleteTextAttachmentCell alloc] initImageCell:anImage]); + scoped_nsobject<NSTextAttachment> attachment( + [[NSTextAttachment alloc] init]); + [attachment setAttachmentCell:attachmentCell]; + + scoped_nsobject<NSMutableAttributedString> 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_; -+ (AutocompleteTextFieldIcon*) - iconWithRect:(NSRect)rect - view:(LocationBarViewMac::LocationBarImageView*)view { - AutocompleteTextFieldIcon* result = [[AutocompleteTextFieldIcon alloc] init]; - [result setRect:rect]; - [result setView:view]; - return [result autorelease]; +// 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_); + } } @end @@ -96,18 +205,40 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { // Adjust for space between editor and decorations. width -= 2 * kEditorHorizontalInset; - // If |fullString| won't fit, choose |partialString|. + // 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|. NSDictionary* attributes = [NSDictionary dictionaryWithObject:[self font] forKey:NSFontAttributeName]; NSString* s = fullString; - if ([s sizeWithAttributes:attributes].width > width) { + const CGFloat sWidth = [s sizeWithAttributes:attributes].width; + if (sWidth + imageSize.width > width) { + image = nil; + } + if (sWidth > width) { if (partialString) { s = partialString; } } - keywordString_.reset( - [[NSAttributedString alloc] initWithString:s attributes:attributes]); + + scoped_nsobject<NSMutableAttributedString> 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]); } // Convenience for the attributes used in the right-justified info @@ -155,21 +286,8 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { initWithString:s attributes:[self hintAttributes]]); // Build an attachment containing the hint image. - scoped_nsobject<NSTextAttachmentCell> attachmentCell( - [[NSTextAttachmentCell alloc] initImageCell:anImage]); - scoped_nsobject<NSTextAttachment> 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<NSMutableAttributedString> is( - [[NSAttributedString attributedStringWithAttachment:attachment] - mutableCopy]); - [is addAttribute:NSBaselineOffsetAttributeName - value:[NSNumber numberWithFloat:kKeywordHintImageBaseline] - range:NSMakeRange(0, [is length])]; + NSAttributedString* is = + AttributedStringForImage(anImage, kKeywordHintImageBaseline); // Stuff the image attachment between the prefix and suffix. [as insertAttributedString:is atIndex:[prefixString length]]; @@ -213,8 +331,16 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { page_action_views_ = list; } -- (void)setSecurityImageView:(LocationBarViewMac::SecurityImageView*)view { - security_image_view_ = view; +- (void)setLocationIconView:(LocationBarViewMac::LocationIconView*)view { + locationIconView_ = view; +} + +- (void)setStarIconView:(LocationBarViewMac::LocationBarImageView*)view { + starIconView_ = view; +} + +- (void)setSecurityLabelView:(LocationBarViewMac::LocationBarImageView*)view { + securityLabelView_ = view; } - (void)setContentSettingViewsList: @@ -226,69 +352,81 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { - (NSRect)textFrameForFrame:(NSRect)cellFrame { NSRect textFrame([super textFrameForFrame:cellFrame]); - if (hintString_) { + // 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_) { 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(cellFrame)) { + if (hintWidth < NSWidth(textFrame)) { textFrame.size.width -= hintWidth; } - } else if (keywordString_) { - DCHECK(!hintString_); - const CGFloat keywordWidth(WidthForKeyword(keywordString_)); + } - // 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); + // 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; } - } 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; } -// 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)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); } -- (NSRect)securityImageFrameForFrame:(NSRect)cellFrame { - if (!security_image_view_ || !security_image_view_->IsVisible()) { +- (NSRect)starIconFrameForFrame:(NSRect)cellFrame { + if (!starIconView_ || !starIconView_->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; - } - return [self rightJustifyImage:imageSize - inRect:cellFrame - withMargin:widthUsed]; + // The star icon is always at the RHS. + scoped_nsobject<AutocompleteTextFieldIcon> icon( + [[AutocompleteTextFieldIcon alloc] initImageWithView:starIconView_]); + cellFrame.size.width -= kHintXOffset; + [icon positionInFrame:cellFrame]; + return [icon rect]; } - (size_t)pageActionCount { @@ -365,118 +503,223 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { [path stroke]; // Draw text w/in the rectangle. - infoFrame.origin.x += 4.0; - infoFrame.origin.y += 1.0; + infoFrame.origin.x += 3.0; [keywordString_.get() drawInRect:infoFrame]; } -- (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]; +- (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; } - // 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]; -} + 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)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]; + // 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; } } + // 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<AutocompleteTextFieldIcon> icon( + [[AutocompleteTextFieldIcon alloc] + initLabelWithView:securityLabelView_]); + [icon positionInFrame:workingFrame]; + [icon drawInView:controlView]; + DCHECK_EQ(labelWidth, NSWidth([icon rect]) + kIconHorizontalPad); + workingFrame.size.width -= NSWidth([icon rect]); + } + } + + // Superclass draws text portion WRT original |cellFrame|. [super drawInteriorWithFrame:cellFrame inView:controlView]; } - (NSArray*)layedOutIcons:(NSRect)cellFrame { - 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 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<LocationBarViewMac::LocationBarImageView*> views; + + if (content_setting_views_) { + views.insert(views.end(), + content_setting_views_->begin(), + content_setting_views_->end()); } - 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); - } + // 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)); } - 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<const LocationBarViewMac::ContentSettingViews*>( - 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); - } + // The star icon should always come last. + if (starIconView_) + views.push_back(starIconView_); + + // Load the visible views into |result|. + for (std::vector<LocationBarViewMac::LocationBarImageView*>::const_iterator + iter = views.begin(); iter != views.end(); ++iter) { + if ((*iter)->IsVisible()) { + scoped_nsobject<AutocompleteTextFieldIcon> icon( + [[AutocompleteTextFieldIcon alloc] initImageWithView:*iter]); + [result addObject:icon]; } } + + // 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; + } return result; } -- (NSMenu*)actionMenuForEvent:(NSEvent*)event - inRect:(NSRect)cellFrame - ofView:(NSView*)aView { - NSPoint location = [aView convertPoint:[event locationInWindow] fromView:nil]; +- (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; + } - const BOOL flipped = [aView isFlipped]; for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) { - if (NSMouseInRect(location, [icon rect], flipped)) { - return [icon view]->GetMenu(); + if (NSMouseInRect(location, [icon rect], flipped)) + return icon; + } + + return nil; +} + +- (NSMenu*)actionMenuForEvent:(NSEvent*)theEvent + inRect:(NSRect)cellFrame + ofView:(AutocompleteTextField*)controlView { + AutocompleteTextFieldIcon* + icon = [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; + if (icon) + return [icon view]->GetMenu(); + return 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; } + + // 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 0a16c48..5bd02cc 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm @@ -4,9 +4,11 @@ #import <Cocoa/Cocoa.h> +#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" @@ -43,7 +45,7 @@ class TestPageActionViewList : public LocationBarViewMac::PageActionViewList { class AutocompleteTextFieldCellTest : public CocoaTest { public: - AutocompleteTextFieldCellTest() : security_image_view_(NULL, NULL, NULL), + AutocompleteTextFieldCellTest() : location_icon_view_(NULL), page_action_views_() { // Make sure this is wide enough to play games with the cell // decorations. @@ -57,7 +59,8 @@ class AutocompleteTextFieldCellTest : public CocoaTest { [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]); [cell setEditable:YES]; [cell setBordered:YES]; - [cell setSecurityImageView:&security_image_view_]; + [cell setLocationIconView:&location_icon_view_]; + [cell setSecurityLabelView:&security_label_view_]; [cell setPageActionViewList:&page_action_views_]; [view_ setCell:cell.get()]; @@ -65,7 +68,8 @@ class AutocompleteTextFieldCellTest : public CocoaTest { } NSTextField* view_; - LocationBarViewMac::SecurityImageView security_image_view_; + LocationBarViewMac::LocationIconView location_icon_view_; + LocationBarViewMac::LocationBarImageView security_label_view_; TestPageActionViewList page_action_views_; }; @@ -199,15 +203,16 @@ TEST_F(AutocompleteTextFieldCellTest, TextFrame) { EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame)); EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); - // Security icon takes up space on the right - security_image_view_.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); - security_image_view_.SetVisible(true); + // Location icon takes up space on the left + location_icon_view_.SetImage( + ResourceBundle::GetSharedInstance().GetNSImageNamed( + IDR_OMNIBOX_HTTPS_VALID)); + location_icon_view_.SetVisible(true); textFrame = [cell textFrameForFrame:bounds]; EXPECT_FALSE(NSIsEmptyRect(textFrame)); EXPECT_TRUE(NSContainsRect(bounds, textFrame)); - EXPECT_LT(NSMaxX(textFrame), NSMaxX(bounds)); + EXPECT_GT(NSMinX(textFrame), NSMinX(bounds)); EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); // Search hint text takes precedence over the hint icon; the text frame @@ -265,9 +270,10 @@ TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) { EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); EXPECT_TRUE(NSEqualRects(drawingRect, originalDrawingRect)); - security_image_view_.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); - security_image_view_.SetVisible(true); + location_icon_view_.SetImage( + ResourceBundle::GetSharedInstance().GetNSImageNamed( + IDR_OMNIBOX_HTTPS_VALID)); + location_icon_view_.SetVisible(true); textFrame = [cell textFrameForFrame:bounds]; drawingRect = [cell drawingRectForBounds:bounds]; @@ -275,55 +281,60 @@ TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) { EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); } -// Test that the security icon is at the right side of the cell. -TEST_F(AutocompleteTextFieldCellTest, SecurityImageFrame) { +// Test that the location icon is at the right side of the cell. +TEST_F(AutocompleteTextFieldCellTest, LocationIconFrame) { AutocompleteTextFieldCell* cell = static_cast<AutocompleteTextFieldCell*>([view_ cell]); const NSRect bounds([view_ bounds]); - security_image_view_.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); - - security_image_view_.SetVisible(false); - EXPECT_EQ(0u, [[cell layedOutIcons:bounds] count]); - - security_image_view_.SetVisible(true); - NSArray* icons = [cell layedOutIcons:bounds]; - ASSERT_EQ(1u, [icons count]); - NSRect iconRect = [[icons objectAtIndex:0] rect]; + location_icon_view_.SetImage( + ResourceBundle::GetSharedInstance().GetNSImageNamed( + IDR_OMNIBOX_HTTPS_VALID)); + location_icon_view_.SetVisible(true); + const NSRect iconRect = [cell locationIconFrameForFrame:bounds]; EXPECT_FALSE(NSIsEmptyRect(iconRect)); EXPECT_TRUE(NSContainsRect(bounds, iconRect)); - // Make sure we are right of the |drawingRect|. - NSRect drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_LE(NSMaxX(drawingRect), NSMinX(iconRect)); + // Location icon should be left of |drawingRect|. + const NSRect drawingRect = [cell drawingRectForBounds:bounds]; + EXPECT_GT(NSMinX(drawingRect), NSMinX(iconRect)); - // Make sure we're right of the |textFrame|. - NSRect textFrame = [cell textFrameForFrame:bounds]; - EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect)); + // Location icon should be left of |textFrame|. + const NSRect textFrame = [cell textFrameForFrame:bounds]; + EXPECT_GT(NSMinX(textFrame), NSMinX(iconRect)); +} + +// Test that security label takes space to the right. +TEST_F(AutocompleteTextFieldCellTest, SecurityLabelFrame) { + AutocompleteTextFieldCell* cell = + static_cast<AutocompleteTextFieldCell*>([view_ cell]); + const NSRect bounds([view_ bounds]); + + // 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])); - // Now add a label. + // Still not visible even with a label. NSFont* font = [NSFont controlContentFontOfSize:12.0]; NSColor* color = [NSColor blackColor]; - security_image_view_.SetLabel(@"Label", font, color); - icons = [cell layedOutIcons:bounds]; - ASSERT_EQ(1u, [icons count]); - iconRect = [[icons objectAtIndex:0] rect]; + security_label_view_.SetLabel(@"Label", font, color); + security_label_view_.SetVisible(false); + EXPECT_TRUE(NSEqualRects(baseTextFrame, [cell textFrameForFrame:bounds])); - EXPECT_FALSE(NSIsEmptyRect(iconRect)); - EXPECT_TRUE(NSContainsRect(bounds, iconRect)); - - // Make sure we are right of the |drawingRect|. - drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_LE(NSMaxX(drawingRect), NSMinX(iconRect)); + // 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); - // Make sure we're right of the |textFrame|. + NSString* longLabel = + @"Really super-long labels will not show up if there's not enough room."; + security_label_view_.SetLabel(longLabel, font, color); textFrame = [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]); + EXPECT_TRUE(NSEqualRects(baseTextFrame, [cell textFrameForFrame:bounds])); } // Test Page Action counts. @@ -349,8 +360,6 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { AutocompleteTextFieldCell* cell = static_cast<AutocompleteTextFieldCell*>([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 @@ -368,13 +377,12 @@ 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 security icon. + // One page action, no lock icon. page_action_view.SetVisible(true); NSRect iconRect0 = [cell pageActionFrameForIndex:0 inFrame:bounds]; @@ -389,17 +397,19 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { NSRect textFrame = [cell textFrameForFrame:bounds]; EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect0)); - // Two page actions plus a security icon. + // Two page actions plus a security label. page_action_view2.SetVisible(true); - security_image_view_.SetVisible(true); NSArray* icons = [cell layedOutIcons:bounds]; - EXPECT_EQ(3u, [icons count]); + ASSERT_EQ(2u, [icons count]); + + // TODO(shess): page-action list is inverted from -layedOutIcons: + // Yes, this is confusing, fix it. iconRect0 = [cell pageActionFrameForIndex:0 inFrame:bounds]; NSRect iconRect1 = [cell pageActionFrameForIndex:1 inFrame:bounds]; - NSRect lockRect = [[icons objectAtIndex:0] rect]; + NSRect labelRect = [[icons objectAtIndex:0] rect]; EXPECT_TRUE(NSEqualRects(iconRect0, [[icons objectAtIndex:1] rect])); - EXPECT_TRUE(NSEqualRects(iconRect1, [[icons objectAtIndex:2] rect])); + EXPECT_TRUE(NSEqualRects(iconRect1, [[icons objectAtIndex:0] rect])); // Make sure they're all in the expected order, and right of the |drawingRect| // and |textFrame|. @@ -410,13 +420,13 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { EXPECT_TRUE(NSContainsRect(bounds, iconRect0)); EXPECT_FALSE(NSIsEmptyRect(iconRect1)); EXPECT_TRUE(NSContainsRect(bounds, iconRect1)); - EXPECT_FALSE(NSIsEmptyRect(lockRect)); - EXPECT_TRUE(NSContainsRect(bounds, lockRect)); + EXPECT_FALSE(NSIsEmptyRect(labelRect)); + EXPECT_TRUE(NSContainsRect(bounds, labelRect)); EXPECT_LE(NSMaxX(drawingRect), NSMinX(iconRect1)); EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect1)); EXPECT_LE(NSMaxX(iconRect1), NSMinX(iconRect0)); - EXPECT_LE(NSMaxX(iconRect0), NSMinX(lockRect)); + EXPECT_LE(NSMaxX(labelRect), NSMinX(iconRect0)); } // Test that the cell correctly chooses the partial keyword if there's @@ -428,11 +438,22 @@ TEST_F(AutocompleteTextFieldCellTest, UsesPartialKeywordIfNarrow) { const NSString* kFullString = @"Search Engine:"; const NSString* kPartialString = @"Search Eng:"; - // Wide width chooses the full string. + // Wide width chooses the full string, including an image on the + // left. [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 70aa5cd..974b346 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_editor.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_editor.mm @@ -33,6 +33,35 @@ 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 d695f86..1d0ae49 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_unittest.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_unittest.mm @@ -4,6 +4,7 @@ #import <Cocoa/Cocoa.h> +#include "app/resource_bundle.h" #import "base/cocoa_protocols_mac.h" #include "base/scoped_nsobject.h" #import "chrome/browser/cocoa/autocomplete_text_field.h" @@ -11,6 +12,7 @@ #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" @@ -20,18 +22,34 @@ using ::testing::Return; using ::testing::StrictMock; namespace { -class MockSecurityImageView : public LocationBarViewMac::SecurityImageView { +class MockLocationIconView : public LocationBarViewMac::LocationIconView { public: - MockSecurityImageView(LocationBarViewMac* owner, - Profile* profile, - ToolbarModel* model) - : LocationBarViewMac::SecurityImageView(owner, profile, model) {} + 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; + } // 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_; }; @@ -582,32 +600,35 @@ TEST_F(AutocompleteTextFieldTest, TripleClickSelectsAll) { } // Clicking the security icon should call its OnMousePressed. -TEST_F(AutocompleteTextFieldObserverTest, SecurityIconMouseDown) { +TEST_F(AutocompleteTextFieldTest, LocationIconMouseDown) { AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; - MockSecurityImageView security_image_view(NULL, NULL, NULL); - [cell setSecurityImageView:&security_image_view]; - security_image_view.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); - security_image_view.SetVisible(true); + 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); - NSRect iconFrame([cell securityImageFrameForFrame:[field_ bounds]]); + NSRect iconFrame([cell locationIconFrameForFrame:[field_ bounds]]); NSPoint location(NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame))); - NSEvent* event(Event(field_, location, NSLeftMouseDown, 1)); + NSEvent* downEvent(Event(field_, location, NSLeftMouseDown, 1)); + NSEvent* upEvent(Event(field_, location, NSLeftMouseUp, 1)); - [field_ mouseDown:event]; - EXPECT_TRUE(security_image_view.mouse_was_pressed_); + // 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()); + + // 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. } // Clicking a Page Action icon should call its OnMousePressed. -TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { +TEST_F(AutocompleteTextFieldTest, 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); @@ -620,8 +641,7 @@ TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { list.Add(&page_action_view2); [cell setPageActionViewList:&list]; - // One page action, no security lock. - security_image_view.SetVisible(false); + // One page action. page_action_view.SetVisible(true); page_action_view2.SetVisible(false); NSRect iconFrame([cell pageActionFrameForIndex:0 inFrame:[field_ bounds]]); @@ -631,7 +651,7 @@ TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { [field_ mouseDown:event]; EXPECT_TRUE(page_action_view.MouseWasPressed()); - // Two page actions, no security lock. + // Two page actions, no lock. page_action_view2.SetVisible(true); iconFrame = [cell pageActionFrameForIndex:0 inFrame:[field_ bounds]]; location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); @@ -647,8 +667,7 @@ TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { [field_ mouseDown:event]; EXPECT_TRUE(page_action_view.MouseWasPressed()); - // Two page actions plus security lock. - security_image_view.SetVisible(true); + // Two page actions. iconFrame = [cell pageActionFrameForIndex:0 inFrame:[field_ bounds]]; location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); event = Event(field_, location, NSLeftMouseDown, 1); @@ -662,13 +681,6 @@ TEST_F(AutocompleteTextFieldObserverTest, 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. @@ -860,4 +872,22 @@ 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 fc2ff7b..465691e 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:kTopLeft]; + [bubble_ setArrowLocation:kTopRight]; // 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 0420c7a..b7e3e64 100644 --- a/chrome/browser/cocoa/browser_test_helper.h +++ b/chrome/browser/cocoa/browser_test_helper.h @@ -25,6 +25,15 @@ 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 f482990..d023663 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_ starButtonInWindowCoordinates]; + NSRect rect = [toolbarController_ starIconInWindowCoordinates]; // 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 5b054fa..d6a3dca 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 left + // As a sanity check make sure the point is vaguely in the top right // of the window. EXPECT_GT(p.y, all.origin.y + (all.size.height/2)); - EXPECT_LT(p.x, all.origin.x + (all.size.width/2)); + EXPECT_GT(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 5a82d67..08e1524 100644 --- a/chrome/browser/cocoa/location_bar_view_mac.h +++ b/chrome/browser/cocoa/location_bar_view_mac.h @@ -24,7 +24,6 @@ #include "third_party/skia/include/core/SkBitmap.h" @class AutocompleteTextField; -class BubblePositioner; class CommandUpdater; class ContentSettingImageModel; @class ExtensionPopupController; @@ -41,7 +40,6 @@ class LocationBarViewMac : public AutocompleteEditController, public NotificationObserver { public: LocationBarViewMac(AutocompleteTextField* field, - const BubblePositioner* bubble_positioner, CommandUpdater* command_updater, ToolbarModel* toolbar_model, Profile* profile, @@ -64,6 +62,9 @@ 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(); } @@ -76,6 +77,13 @@ 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). @@ -124,7 +132,6 @@ 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. @@ -142,7 +149,9 @@ class LocationBarViewMac : public AutocompleteEditController, // Sets the image. void SetImage(NSImage* image); - void SetImage(SkBitmap* image); + + // Get the |resource_id| image resource and set the image. + void SetIcon(int resource_id); // Sets the label text, font, and color. |text| may be nil; |color| and // |font| are ignored if |text| is nil. @@ -156,9 +165,21 @@ 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) {} @@ -176,42 +197,50 @@ class LocationBarViewMac : public AutocompleteEditController, DISALLOW_COPY_AND_ASSIGN(LocationBarImageView); }; - // SecurityImageView is used to display the lock or warning icon when the - // current URL's scheme is https. - class SecurityImageView : public LocationBarImageView { + // LocationIconView is used to display an icon to the left of the address. + class LocationIconView : public LocationBarImageView { public: - enum Image { - LOCK = 0, - WARNING - }; + explicit LocationIconView(LocationBarViewMac* owner); + virtual ~LocationIconView(); - SecurityImageView(LocationBarViewMac* owner, - Profile* profile, - ToolbarModel* model); - virtual ~SecurityImageView(); + // Is draggable if the autocomplete edit view has not be changed. + virtual bool IsDraggable(); - // Sets the image to the appropriate icon. - void SetImageShown(Image image); + // Drag the URL and title from the current tab. + virtual NSPasteboard* GetDragPasteboard(); // Shows the page info dialog. virtual void OnMousePressed(NSRect bounds); private: - // The lock icon shown when using HTTPS. Loaded lazily, the first time it's - // needed. - scoped_nsobject<NSImage> lock_icon_; - - // The warning icon shown when HTTPS is broken. Loaded lazily, the first - // time it's needed. - scoped_nsobject<NSImage> warning_icon_; - // The location bar view that owns us. LocationBarViewMac* owner_; - Profile* profile_; - ToolbarModel* model_; + DISALLOW_COPY_AND_ASSIGN(LocationIconView); + }; - DISALLOW_COPY_AND_ASSIGN(SecurityImageView); + // Used to display the bookmark star in the RHS. + class StarIconView : public LocationBarImageView { + public: + explicit StarIconView(CommandUpdater* command_updater); + virtual ~StarIconView() {} + + // 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 string to show for a tooltip. + scoped_nsobject<NSString> tooltip_; + + DISALLOW_COPY_AND_ASSIGN(StarIconView); }; // PageActionImageView is used to display the icon for a given Page Action @@ -231,14 +260,13 @@ class LocationBarViewMac : public AutocompleteEditController, void set_preview_enabled(bool enabled) { preview_enabled_ = enabled; } - bool preview_enabled() { return preview_enabled_; } + bool preview_enabled() const { 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 GetPreferredImageSize(); + virtual NSSize GetDefaultImageSize() const; // Either notify listeners or show a popup depending on the Page Action. virtual void OnMousePressed(NSRect bounds); @@ -384,11 +412,11 @@ class LocationBarViewMac : public AutocompleteEditController, }; private: - // Sets the SSL icon we should be showing. - void SetSecurityIcon(ToolbarModel::Icon icon); + // Sets the location icon we should be showing. + void SetIcon(int resource_id); - // Sets the label for the SSL icon. - void SetSecurityIconLabel(); + // Sets the label for the SSL state. + void SetSecurityLabel(); // Posts |notification| to the default notification center. void PostNotification(const NSString* notification); @@ -411,8 +439,14 @@ class LocationBarViewMac : public AutocompleteEditController, // The user's desired disposition for how their input should be opened. WindowOpenDisposition disposition_; - // The view that shows the lock/warning when in HTTPS mode. - SecurityImageView security_image_view_; + // 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_; // 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 dde3095..35751dc 100644 --- a/chrome/browser/cocoa/location_bar_view_mac.mm +++ b/chrome/browser/cocoa/location_bar_view_mac.mm @@ -41,6 +41,7 @@ #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 @@ -62,11 +63,13 @@ std::wstring GetKeywordName(Profile* profile, const std::wstring& keyword) { return std::wstring(); } -// 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; +// 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; // Build a short string to use in keyword-search when the field isn't // very big. @@ -91,17 +94,18 @@ 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, bubble_positioner, - toolbar_model, profile, command_updater, field)), + : edit_view_(new AutocompleteEditViewMac(this, toolbar_model, profile, + command_updater, field)), command_updater_(command_updater), field_(field), disposition_(CURRENT_TAB), - security_image_view_(this, profile, toolbar_model), + location_icon_view_(this), + security_label_view_(), + star_icon_view_(command_updater), page_action_views_(this, profile, toolbar_model), profile_(profile), browser_(browser), @@ -116,7 +120,9 @@ LocationBarViewMac::LocationBarViewMac( } AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; - [cell setSecurityImageView:&security_image_view_]; + [cell setLocationIconView:&location_icon_view_]; + [cell setSecurityLabelView:&security_label_view_]; + [cell setStarIconView:&star_icon_view_]; [cell setPageActionViewList:&page_action_views_]; [cell setContentSettingViewsList:&content_setting_views_]; @@ -129,7 +135,9 @@ LocationBarViewMac::~LocationBarViewMac() { // Disconnect from cell in case it outlives us. AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; [cell setPageActionViewList:NULL]; - [cell setSecurityImageView:NULL]; + [cell setLocationIconView:NULL]; + [cell setSecurityLabelView:NULL]; + [cell setStarIconView:NULL]; } std::wstring LocationBarViewMac::GetInputString() const { @@ -206,7 +214,7 @@ void LocationBarViewMac::SaveStateToContents(TabContents* contents) { void LocationBarViewMac::Update(const TabContents* contents, bool should_restore_state) { - SetSecurityIcon(toolbar_model_->GetIcon()); + SetIcon(edit_view_->GetIcon()); page_action_views_.RefreshViews(); RefreshContentSettingsViews(); // AutocompleteEditView restores state if the tab is non-NULL. @@ -252,7 +260,6 @@ 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]); @@ -298,12 +305,6 @@ 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]; @@ -330,7 +331,6 @@ void LocationBarViewMac::OnChanged() { keyword, short_name, edit_view_->model()->is_keyword_hint(), - edit_view_->model()->show_search_hint(), GetTabButtonImage()); } @@ -444,6 +444,22 @@ 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(). @@ -455,44 +471,37 @@ NSImage* LocationBarViewMac::GetTabButtonImage() { return tab_button_image_; } -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); +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); } else { - security_image_view_.SetLabel(nil, nil, nil); + NSImage* image = AutocompleteEditViewMac::ImageForResource(resource_id); + location_icon_view_.SetImage(image); + location_icon_view_.SetVisible(true); + SetSecurityLabel(); } + [field_ resetFieldEditorFrameIfNeeded]; } -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; +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); } - [field_ resetFieldEditorFrameIfNeeded]; } void LocationBarViewMac::Observe(NotificationType type, @@ -535,8 +544,9 @@ void LocationBarViewMac::LocationBarImageView::SetImage(NSImage* image) { image_.reset([image retain]); } -void LocationBarViewMac::LocationBarImageView::SetImage(SkBitmap* image) { - SetImage(gfx::SkBitmapToNSImage(*image)); +void LocationBarViewMac::LocationBarImageView::SetIcon(int resource_id) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + SetImage(rb.GetNSImageNamed(resource_id)); } void LocationBarViewMac::LocationBarImageView::SetLabel(NSString* text, @@ -564,43 +574,32 @@ void LocationBarViewMac::LocationBarImageView::SetVisible(bool visible) { visible_ = visible; } -// SecurityImageView------------------------------------------------------------ +NSSize LocationBarViewMac::LocationBarImageView::GetDefaultImageSize() const { + return NSZeroSize; +} -LocationBarViewMac::SecurityImageView::SecurityImageView( - LocationBarViewMac* owner, - Profile* profile, - ToolbarModel* model) - : lock_icon_(nil), - warning_icon_(nil), - owner_(owner), - profile_(profile), - model_(model) {} +NSSize LocationBarViewMac::LocationBarImageView::GetImageSize() const { + NSImage* image = GetImage(); + if (image) + return [image size]; + return GetDefaultImageSize(); +} -LocationBarViewMac::SecurityImageView::~SecurityImageView() {} +// LocationIconView ------------------------------------------------------------ -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( + LocationBarViewMac* owner) + : owner_(owner) { } -void LocationBarViewMac::SecurityImageView::OnMousePressed(NSRect bounds) { +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; + TabContents* tab = owner_->GetTabContents(); NavigationEntry* nav_entry = tab->controller().GetActiveEntry(); if (!nav_entry) { @@ -610,6 +609,57 @@ void LocationBarViewMac::SecurityImageView::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( @@ -647,14 +697,9 @@ LocationBarViewMac::PageActionImageView::PageActionImageView( LocationBarViewMac::PageActionImageView::~PageActionImageView() { } -NSSize LocationBarViewMac::PageActionImageView::GetPreferredImageSize() { - NSImage* image = GetImage(); - if (image) { - return [image size]; - } else { - return NSMakeSize(Extension::kPageActionIconMaxSize, - Extension::kPageActionIconMaxSize); - } +NSSize LocationBarViewMac::PageActionImageView::GetDefaultImageSize() const { + return NSMakeSize(Extension::kPageActionIconMaxSize, + Extension::kPageActionIconMaxSize); } // Overridden from LocationBarImageView. Either notify listeners or show a @@ -868,10 +913,9 @@ 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 - SetImage(rb.GetNSImageNamed(content_setting_image_model_->get_icon())); + SetIcon(content_setting_image_model_->get_icon()); SetToolTip(base::SysUTF8ToNSString( content_setting_image_model_->get_tooltip())); SetVisible(true); @@ -895,6 +939,11 @@ void LocationBarViewMac::PageActionViewList::DeleteAll() { } void LocationBarViewMac::PageActionViewList::RefreshViews() { + if (!owner_->IsEditable()) { + DeleteAll(); + return; + } + std::vector<ExtensionAction*> 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 aec948d..ecb2a7b 100644 --- a/chrome/browser/cocoa/location_bar_view_mac_unittest.mm +++ b/chrome/browser/cocoa/location_bar_view_mac_unittest.mm @@ -81,7 +81,6 @@ 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:"; @@ -90,39 +89,20 @@ 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, false, image); + LocationBarViewMac::OnChangedImpl(field_, std::wstring(), std::wstring(), false, image); EXPECT_FALSE([cell keywordString]); EXPECT_FALSE([cell hintString]); - // 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); + // Request a keyword hint. + LocationBarViewMac::OnChangedImpl(field_, kKeyword, kKeyword, true, image); EXPECT_FALSE([cell keywordString]); EXPECT_TRUE([[[cell hintString] string] hasPrefix:kKeywordPrefix]); EXPECT_TRUE([[[cell hintString] string] hasSuffix:kKeywordSuffix]); - // Request keyword-search mode, same results whether |search_hint| - // parameter is true or false. + // Request keyword-search mode. LocationBarViewMac::OnChangedImpl( - 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]); + field_, kKeyword, kKeyword, false, image); + EXPECT_TRUE([[[cell keywordString] string] hasSuffix:kKeywordString]); EXPECT_FALSE([cell hintString]); // Check that a partial keyword-search string is passed down in case @@ -132,14 +112,13 @@ TEST_F(LocationBarViewMacTest, OnChangedImpl) { NSRect frame([field_ frame]); frame.size.width = 10.0; [field_ setFrame:frame]; - LocationBarViewMac::OnChangedImpl( - field_, kKeyword, kKeyword, false, true, image); + LocationBarViewMac::OnChangedImpl(field_, kKeyword, kKeyword, false, image); EXPECT_TRUE([[[cell keywordString] string] isEqualToString:kPartialString]); EXPECT_FALSE([cell hintString]); // Transition back to baseline. LocationBarViewMac::OnChangedImpl( - field_, std::wstring(), std::wstring(), false, false, image); + field_, std::wstring(), std::wstring(), 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 3dd628e..6f4dab4 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:@"http://www.cnn.com/"]); + EXPECT_TRUE([GetURLText() isEqualToString:@"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:@"http://www.nytimes.com/"]); + EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"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:@"http://www.nytimes.com/"]); + EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"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:@"http://www.nytimes.com/"]); + EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"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 0967ae4..82cea8e 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) 2009 The Chromium Authors. All rights reserved. +// 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. diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h index 0fdd8c4..1f277c1 100644 --- a/chrome/browser/cocoa/toolbar_controller.h +++ b/chrome/browser/cocoa/toolbar_controller.h @@ -22,7 +22,6 @@ class AppMenuModel; @class BackForwardMenuController; class Browser; @class BrowserActionsController; -class BubblePositioner; class CommandUpdater; @class DelayedMenuButton; class LocationBar; @@ -70,8 +69,6 @@ class ToolbarModel; // Used for monitoring the optional toolbar button prefs. scoped_ptr<ToolbarControllerInternal::PrefObserverBridge> prefObserver_; - // Used to position the omnibox bubble. - scoped_ptr<BubblePositioner> bubblePositioner_; BooleanPrefMember showHomeButton_; BooleanPrefMember showPageOptionButtons_; BOOL hasToolbar_; // If NO, we may have only the location bar. @@ -99,7 +96,6 @@ class ToolbarModel; IBOutlet DelayedMenuButton* forwardButton_; IBOutlet NSButton* reloadButton_; IBOutlet NSButton* homeButton_; - IBOutlet NSButton* starButton_; IBOutlet NSButton* goButton_; IBOutlet MenuButton* pageButton_; IBOutlet MenuButton* wrenchButton_; @@ -147,9 +143,10 @@ 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) needs to know where to go. -// Somewhere near the star button seems like a good start. -- (NSRect)starButtonInWindowCoordinates; +// 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; // Returns the desired toolbar height for the given compression factor. - (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight; @@ -171,7 +168,6 @@ 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 1412fc1..a9c4a33 100644 --- a/chrome/browser/cocoa/toolbar_controller.mm +++ b/chrome/browser/cocoa/toolbar_controller.mm @@ -15,7 +15,6 @@ #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" @@ -51,8 +50,6 @@ 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"; @@ -87,26 +84,6 @@ 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 @@ -225,7 +202,6 @@ 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)]; @@ -234,9 +210,7 @@ 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]]]; @@ -312,10 +286,6 @@ 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 @@ -393,9 +363,6 @@ class PrefObserverBridge : public NotificationObserver { case IDC_HOME: button = homeButton_; break; - case IDC_BOOKMARK_PAGE: - button = starButton_; - break; } [button setEnabled:enabled]; } @@ -408,8 +375,6 @@ 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 @@ -424,23 +389,7 @@ class PrefObserverBridge : public NotificationObserver { } - (void)setStarredState:(BOOL)isStarred { - 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]; + locationBarView_->SetStarred(isStarred ? true : false); } - (void)setIsLoading:(BOOL)isLoading { @@ -469,7 +418,7 @@ class PrefObserverBridge : public NotificationObserver { // Make location bar not editable when in a pop-up. // TODO(viettrungluu): is this right (all the time)? - [locationBar_ setEditable:toolbar]; + locationBarView_->SetEditable(toolbar ? true : false); } - (NSView*)view { @@ -507,7 +456,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_, starButton_, goButton_, pageButton_, wrenchButton_, + homeButton_, goButton_, pageButton_, wrenchButton_, locationBar_, browserActionsContainerView_, nil]; } @@ -520,14 +469,16 @@ class PrefObserverBridge : public NotificationObserver { return frame; } -// 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. +// 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. - (CGFloat)interButtonSpacing { - NSRect forwardFrame = [forwardButton_ frame]; - NSRect reloadFrame = [reloadButton_ frame]; - DCHECK(NSMinX(reloadFrame) > NSMaxX(forwardFrame)); - return NSMinX(reloadFrame) - NSMaxX(forwardFrame); + 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); } // Show or hide the home button based on the pref. @@ -546,7 +497,7 @@ class PrefObserverBridge : public NotificationObserver { if (hide) moveX *= -1; // Reverse the direction of the move. - [starButton_ setFrame:NSOffsetRect([starButton_ frame], moveX, 0)]; + [reloadButton_ setFrame:NSOffsetRect([reloadButton_ frame], moveX, 0)]; [locationBar_ setFrame:[self adjustRect:[locationBar_ frame] byAmount:moveX]]; [homeButton_ setHidden:hide]; @@ -769,8 +720,8 @@ class PrefObserverBridge : public NotificationObserver { [NSAnimationContext endGrouping]; } -- (NSRect)starButtonInWindowCoordinates { - return [starButton_ convertRect:[starButton_ bounds] toView:nil]; +- (NSRect)starIconInWindowCoordinates { + return [locationBar_ convertRect:[locationBar_ starIconFrame] toView:nil]; } - (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight { @@ -845,31 +796,6 @@ 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 7c718c4..dcea565 100644 --- a/chrome/browser/cocoa/toolbar_controller_unittest.mm +++ b/chrome/browser/cocoa/toolbar_controller_unittest.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -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, kStarIndex, kGoIndex, + kBackIndex, kForwardIndex, kReloadIndex, kHomeIndex, kGoIndex, kPageIndex, kWrenchIndex, kLocationIndex, kBrowserActionContainerViewIndex }; @@ -78,8 +78,6 @@ 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_; @@ -160,16 +158,16 @@ TEST_F(ToolbarControllerTest, ToggleHome) { NSView* homeButton = [[bar_ toolbarViews] objectAtIndex:kHomeIndex]; EXPECT_EQ(showHome, ![homeButton isHidden]); - NSView* starButton = [[bar_ toolbarViews] objectAtIndex:kStarIndex]; + NSView* reloadButton = [[bar_ toolbarViews] objectAtIndex:kReloadIndex]; NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex]; - NSRect originalStarFrame = [starButton frame]; + NSRect originalReloadFrame = [reloadButton 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(originalStarFrame), NSMinX([starButton frame])); + EXPECT_NE(NSMinX(originalReloadFrame), NSMinX([reloadButton frame])); EXPECT_NE(NSMinX(originalLocationBarFrame), NSMinX([locationBar frame])); EXPECT_NE(NSWidth(originalLocationBarFrame), NSWidth([locationBar frame])); } @@ -220,32 +218,14 @@ TEST_F(ToolbarControllerTest, DontToggleWhenNoToolbar) { EXPECT_TRUE(NSEqualRects(locationBarFrame, newLocationBarFrame)); } -TEST_F(ToolbarControllerTest, StarButtonInWindowCoordinates) { - NSRect star = [bar_ starButtonInWindowCoordinates]; +TEST_F(ToolbarControllerTest, StarIconInWindowCoordinates) { + NSRect star = [bar_ starIconInWindowCoordinates]; 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<HitView> 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 21ffe03..c93d8f0 100644 --- a/chrome/browser/gtk/accelerators_gtk.cc +++ b/chrome/browser/gtk/accelerators_gtk.cc @@ -151,8 +151,7 @@ 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_CONTROL_MASK }, - { GDK_b, IDC_SHOW_BOOKMARK_MANAGER, + { GDK_b, IDC_SHOW_BOOKMARK_BAR, 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 524c9c3..2bf86e2 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 a4e79b0..bfe25fc 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.cc +++ b/chrome/browser/gtk/browser_toolbar_gtk.cc @@ -35,7 +35,6 @@ #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" @@ -66,17 +65,13 @@ 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(this, browser)), + location_bar_(new LocationBarViewGtk(browser)), model_(browser->toolbar_model()), page_menu_model_(this, browser), app_menu_model_(this, browser), @@ -160,11 +155,6 @@ 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), @@ -172,23 +162,25 @@ 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); - 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_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(), @@ -227,17 +219,16 @@ 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(star_->widget()); + gtk_widget_show_all(location_hbox_); + gtk_widget_hide(reload_->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()); @@ -248,6 +239,7 @@ void BrowserToolbarGtk::Init(Profile* profile, location_bar_->UpdateContentSettingsIcons(); SetViewIDs(); + theme_provider_->InitThemesFor(this); } void BrowserToolbarGtk::SetViewIDs() { @@ -256,7 +248,6 @@ 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); @@ -312,9 +303,6 @@ 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) { @@ -410,6 +398,19 @@ 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. @@ -445,38 +446,6 @@ 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( @@ -498,18 +467,6 @@ 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) { @@ -579,42 +536,9 @@ 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, - &rec); + &location_hbox->allocation); } return FALSE; @@ -639,8 +563,6 @@ 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 1ece0db..9c5f2c8 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.h +++ b/chrome/browser/gtk/browser_toolbar_gtk.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -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,7 +35,6 @@ 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. @@ -44,7 +43,6 @@ 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); @@ -113,11 +111,6 @@ 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, @@ -135,9 +128,6 @@ 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, @@ -191,14 +181,16 @@ 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<LocationBarViewGtk> location_bar_; // All the buttons in the toolbar. scoped_ptr<BackForwardButtonGtk> back_, forward_; - scoped_ptr<CustomDrawButton> reload_; scoped_ptr<CustomDrawButton> home_; - scoped_ptr<ToolbarStarToggleGtk> star_; + scoped_ptr<CustomDrawButton> reload_; scoped_ptr<GoButtonGtk> go_; scoped_ptr<BrowserActionsToolbarGtk> 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 3eba2c5..5bdb347 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -57,6 +57,7 @@ #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" @@ -65,7 +66,6 @@ #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_->star()->SetStarred(is_starred); + toolbar_->GetLocationBarView()->SetStarred(is_starred); } gfx::Rect BrowserWindowGtk::GetRestoredBounds() const { @@ -845,7 +845,7 @@ void BrowserWindowGtk::ShowBookmarkManager() { void BrowserWindowGtk::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) { - toolbar_->star()->ShowStarBubble(url, !already_bookmarked); + toolbar_->GetLocationBarView()->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 e3bc7ff..b8785da 100644 --- a/chrome/browser/gtk/find_bar_gtk.cc +++ b/chrome/browser/gtk/find_bar_gtk.cc @@ -456,6 +456,7 @@ 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); @@ -482,6 +483,7 @@ 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 2f0f142..24e7266 100644 --- a/chrome/browser/gtk/gtk_theme_provider.cc +++ b/chrome/browser/gtk/gtk_theme_provider.cc @@ -91,10 +91,30 @@ 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<int> images; if (images.empty()) { images.insert(kThemeImages, kThemeImages + arraysize(kThemeImages)); + images.insert(kAutocompleteImages, + kAutocompleteImages + arraysize(kAutocompleteImages)); const std::set<int>& buttons = BrowserThemeProvider::GetTintableToolbarButtons(); @@ -738,15 +758,49 @@ 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<SkBitmap> button(new SkBitmap(*rb.GetBitmapNamed(id))); TintMap::const_iterator it = tints_.find( BrowserThemeProvider::TINT_BUTTONS); DCHECK(it != tints_.end()); - return new SkBitmap(SkBitmapOperations::CreateHSLShiftedBitmap( - *button, it->second)); + return GenerateTintedIcon(id, it->second); } } } @@ -768,6 +822,20 @@ 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<SkBitmap> 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<GtkWidget*>::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 23c0a57..227bbbe 100644 --- a/chrome/browser/gtk/gtk_theme_provider.h +++ b/chrome/browser/gtk/gtk_theme_provider.h @@ -163,6 +163,13 @@ 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 3013b12..4d5796a 100644 --- a/chrome/browser/gtk/gtk_util.cc +++ b/chrome/browser/gtk/gtk_util.cc @@ -17,11 +17,13 @@ #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" @@ -869,4 +871,32 @@ 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 e28778a..1d8b6d3 100644 --- a/chrome/browser/gtk/gtk_util.h +++ b/chrome/browser/gtk/gtk_util.h @@ -17,6 +17,8 @@ typedef struct _GtkWidget GtkWidget; class GtkThemeProvider; +class GURL; +class Profile; struct RendererPreferences; // from common/renderer_preferences.h namespace event_utils { @@ -270,6 +272,11 @@ 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 7c0685c..18eda70 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/gtk/location_bar_view_gtk.cc @@ -6,6 +6,7 @@ #include <string> +#include "app/gtk_dnd_util.h" #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/basictypes.h" @@ -26,6 +27,7 @@ #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" @@ -33,6 +35,7 @@ #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" @@ -73,10 +76,12 @@ const int kHboxBorder = 4; // Padding between the elements in the bar. static const int kInnerPadding = 4; -// 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. +// 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. const GdkColor kKeywordBackgroundColor = GDK_COLOR_RGB(0xf0, 0xf4, 0xfa); const GdkColor kKeywordBorderColor = GDK_COLOR_RGB(0xcb, 0xde, 0xf7); @@ -131,19 +136,22 @@ std::wstring CalculateMinString(const std::wstring& description) { // LocationBarViewGtk // static -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), +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), security_warning_icon_image_(NULL), - info_label_(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), tab_to_search_box_(NULL), tab_to_search_full_label_(NULL), tab_to_search_partial_label_(NULL), @@ -151,12 +159,10 @@ LocationBarViewGtk::LocationBarViewGtk( 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), @@ -164,12 +170,12 @@ LocationBarViewGtk::LocationBarViewGtk( theme_provider_(NULL), entry_box_width_(0), show_selected_keyword_(false), - show_keyword_hint_(false), - show_search_hint_(false) { + show_keyword_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(); @@ -177,14 +183,8 @@ 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,30 +193,23 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { // the home button on/off. gtk_widget_set_redraw_on_allocate(hbox_.get(), TRUE); - 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"); + // Now initialize the AutocompleteEditViewGtk. + location_entry_.reset(new AutocompleteEditViewGtk(this, + toolbar_model_, + profile_, + command_updater_, + popup_window_mode_, + hbox_.get())); + location_entry_->Init(); g_signal_connect(hbox_.get(), "expose-event", G_CALLBACK(&HandleExposeThunk), this); - // 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. + 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. GtkWidget* entry_box = gtk_hbox_new(FALSE, kInnerPadding); gtk_widget_show(entry_box); gtk_widget_set_size_request(entry_box, 0, -1); @@ -237,13 +230,22 @@ 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_label_fixed, NULL, 1, 1, 2, 2); + tab_to_search_hbox, NULL, 1, 1, 1, 3); gtk_widget_set_name(tab_to_search_box_, "chrome-tab-to-search-box"); - gtk_util::ActAsRoundedWindow(tab_to_search_box_, kBorderColor, kCornerSize, + gtk_util::ActAsRoundedWindow(tab_to_search_box_, kKeywordBorderColor, + 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_|. @@ -269,7 +271,7 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { kBottomMargin + kBorderThickness, 0, 0); } - gtk_container_add(GTK_CONTAINER(align), location_entry_->widget()); + gtk_container_add(GTK_CONTAINER(align), location_entry_->GetNativeView()); gtk_box_pack_start(GTK_BOX(entry_box), align, TRUE, TRUE, 0); // Tab to search notification (the hint on the right hand side). @@ -297,36 +299,11 @@ 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); - // 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); + // 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); + } content_setting_hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding)); gtk_widget_set_name(content_setting_hbox_.get(), @@ -350,9 +327,7 @@ 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(type_to_search_hint_, - browser_defaults::kAutocompleteEditFontPixelSize); - gtk_util::ForceFontSizePixels(info_label_, + gtk_util::ForceFontSizePixels(security_info_label_, browser_defaults::kAutocompleteEditFontPixelSize); gtk_util::ForceFontSizePixels(tab_to_search_full_label_, browser_defaults::kAutocompleteEditFontPixelSize); @@ -362,8 +337,6 @@ 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, @@ -372,6 +345,71 @@ 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; } @@ -410,10 +448,9 @@ GtkWidget* LocationBarViewGtk::GetPageActionWidget( } void LocationBarViewGtk::Update(const TabContents* contents) { - SetSecurityIcon(toolbar_model_->GetIcon()); + UpdateSiteTypeArea(); UpdateContentSettingsIcons(); UpdatePageActions(); - SetInfoText(); location_entry_->Update(contents); // The security level (background color) could have changed, etc. if (theme_provider_->UseGtkTheme()) { @@ -461,12 +498,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); @@ -477,6 +514,20 @@ 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. @@ -612,7 +663,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()) + if (PageActionVisibleCount() && !ShouldOnlyShowLocation()) gtk_widget_show(page_action_hbox_.get()); else gtk_widget_hide(page_action_hbox_.get()); @@ -691,11 +742,6 @@ 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); @@ -708,12 +754,11 @@ void LocationBarViewGtk::Observe(NotificationType type, &kHintTextColor); gtk_util::SetLabelColor(tab_to_search_hint_trailing_label_, &kHintTextColor); - gtk_util::SetLabelColor(type_to_search_hint_, &kHintTextColor); - - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - gtk_image_set_from_pixbuf(GTK_IMAGE(security_warning_icon_image_), - rb.GetPixbufNamed(IDR_WARNING)); } + + UpdateStarIcon(); + UpdateSiteTypeArea(); + UpdateContentSettingsIcons(); } gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget, @@ -746,8 +791,7 @@ gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget, alloc_rect->width, alloc_rect->height - kTopMargin - kBottomMargin - 2 * kBorderThickness); - gdk_cairo_set_source_color(cr, const_cast<GdkColor*>( - &kBackgroundColorByLevel[toolbar_model_->GetSchemeSecurityLevel()])); + gdk_cairo_set_source_color(cr, const_cast<GdkColor*>(&kBackgroundColor)); cairo_fill(cr); cairo_destroy(cr); @@ -756,45 +800,52 @@ gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget, return FALSE; // Continue propagating the expose. } -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; +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::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_)); + 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_)); } else { - 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_)); + 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_)); } - 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()); + + gtk_widget_show(site_type_area()); + + SetSiteTypeDragSource(); } void LocationBarViewGtk::SetKeywordLabel(const std::wstring& keyword) { @@ -865,46 +916,114 @@ void LocationBarViewGtk::ShowFirstRunBubbleInternal( FirstRunBubble::Show(profile_, anchor, rect, bubble_type); } -// 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; +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; } - tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true); - 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); } -void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkAllocation* allocation) { +void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkWidget* sender, + 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_|, |tab_to_search_hint_| and - // |type_to_search_hint_| can be visible at the same time. + // Only one of |tab_to_search_box_| and |tab_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); @@ -953,13 +1072,6 @@ 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_); } } @@ -997,14 +1109,12 @@ 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()) { - if (old_icon != content_setting_image_model_->get_icon()) { - gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), - ResourceBundle::GetSharedInstance().GetPixbufNamed( + gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), + GtkThemeProvider::GetFrom(profile_)->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 97ac60c6..fe9d26c 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.h +++ b/chrome/browser/gtk/location_bar_view_gtk.h @@ -10,6 +10,7 @@ #include <map> #include <string> +#include "app/gtk_signal.h" #include "base/basictypes.h" #include "base/scoped_ptr.h" #include "base/scoped_vector.h" @@ -30,7 +31,6 @@ #include "webkit/glue/window_open_disposition.h" class AutocompleteEditViewGtk; -class BubblePositioner; class Browser; class CommandUpdater; class ContentSettingImageModel; @@ -47,8 +47,7 @@ class LocationBarViewGtk : public AutocompleteEditController, public LocationBarTesting, public NotificationObserver { public: - LocationBarViewGtk(const BubblePositioner* bubble_positioner, - Browser* browser_); + explicit LocationBarViewGtk(Browser* browser); virtual ~LocationBarViewGtk(); void Init(bool popup_window_mode); @@ -78,6 +77,12 @@ 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, @@ -104,6 +109,9 @@ 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(); } @@ -121,9 +129,8 @@ class LocationBarViewGtk : public AutocompleteEditController, const NotificationSource& source, const NotificationDetails& details); - // 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]; + // Edit background color. + static const GdkColor kBackgroundColor; private: class ContentSettingImageViewGtk : public InfoBubbleGtkDelegate { @@ -141,12 +148,8 @@ class LocationBarViewGtk : public AutocompleteEditController, void UpdateFromTabContents(const TabContents* tab_contents); private: - static gboolean OnButtonPressedThunk(GtkWidget* sender, - GdkEvent* event, - ContentSettingImageViewGtk* view) { - return view->OnButtonPressed(sender, event); - } - gboolean OnButtonPressed(GtkWidget* sender, GdkEvent* event); + CHROMEGTK_CALLBACK_1(ContentSettingImageViewGtk, gboolean, OnButtonPressed, + GdkEvent*); // InfoBubbleDelegate overrides: virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, @@ -208,19 +211,10 @@ class LocationBarViewGtk : public AutocompleteEditController, // with a debugger window attached. Returns true if a popup was shown. bool ShowPopup(bool devtools); - 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); + CHROMEGTK_CALLBACK_1(PageActionViewGtk, gboolean, OnButtonPressed, + GdkEvent*); + CHROMEGTK_CALLBACK_1(PageActionViewGtk, gboolean, OnExposeEvent, + GdkEventExpose*); // The location bar view that owns us. LocationBarViewGtk* owner_; @@ -268,20 +262,30 @@ class LocationBarViewGtk : public AutocompleteEditController, }; friend class PageActionViewGtk; - static gboolean HandleExposeThunk(GtkWidget* widget, GdkEventExpose* event, - gpointer userdata) { - return reinterpret_cast<LocationBarViewGtk*>(userdata)-> - HandleExpose(widget, event); - } + // 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(); - gboolean HandleExpose(GtkWidget* widget, GdkEventExpose* event); + GtkWidget* site_type_area() { return site_type_alignment_; } - static gboolean OnSecurityIconPressed(GtkWidget* sender, - GdkEventButton* event, - LocationBarViewGtk* location_bar); + 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*); - // Set the SSL icon we should be showing. - void SetSecurityIcon(ToolbarModel::Icon icon); + // Updates the site type area: changes the icon and shows/hides the EV + // certificate information. + void UpdateSiteTypeArea(); // 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 @@ -296,29 +300,43 @@ class LocationBarViewGtk : public AutocompleteEditController, void ShowFirstRunBubbleInternal(FirstRun::BubbleType bubble_type); - static void OnEntryBoxSizeAllocateThunk(GtkWidget* widget, - GtkAllocation* allocation, - gpointer userdata) { - reinterpret_cast<LocationBarViewGtk*>(userdata)-> - OnEntryBoxSizeAllocate(allocation); - } - void OnEntryBoxSizeAllocate(GtkAllocation* allocation); - - // 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. + // 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(); + + // Returns true if we should only show the URL and none of the extras like + // the star button or page actions. + bool ShouldOnlyShowLocation(); + // The outermost widget we want to be hosted. OwnedWidgetGtk hbox_; - // SSL icons. + // Star button. + OwnedWidgetGtk star_; + GtkWidget* star_image_; + bool starred_; + + // SSL state. GtkWidget* security_icon_event_box_; - GtkWidget* security_lock_icon_image_; + GtkWidget* ev_secure_icon_image_; + GtkWidget* secure_icon_image_; GtkWidget* security_warning_icon_image_; - // Toolbar info text (EV cert info). - GtkWidget* info_label_; + 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_; // Content setting icons. OwnedWidgetGtk content_setting_hbox_; @@ -339,9 +357,6 @@ 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<AutocompleteEditViewGtk> location_entry_; Profile* profile_; @@ -349,9 +364,6 @@ 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(). @@ -385,9 +397,6 @@ 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 5488e4f..8162610 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, - false, UnescapeRule::NONE, NULL, NULL, NULL); + net::kFormatUrlOmitAll, 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 0de0403..9ecf89f 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) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -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, - false, UnescapeRule::NONE, NULL, NULL, NULL); + net::kFormatUrlOmitAll, 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 df45b14..b5e5a5b 100644 --- a/chrome/browser/gtk/options/url_picker_dialog_gtk.cc +++ b/chrome/browser/gtk/options/url_picker_dialog_gtk.cc @@ -198,7 +198,8 @@ 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, false, UnescapeRule::NONE, NULL, NULL, NULL); + languages, net::kFormatUrlOmitNothing, 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 540a465..52bedc9 100644 --- a/chrome/browser/gtk/rounded_window.cc +++ b/chrome/browser/gtk/rounded_window.cc @@ -287,6 +287,10 @@ 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 95f91d9..cd98e71 100644 --- a/chrome/browser/gtk/rounded_window.h +++ b/chrome/browser/gtk/rounded_window.h @@ -42,6 +42,9 @@ 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 25a02c3..8d1d1c8 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc @@ -1980,28 +1980,8 @@ 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. - 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()) + GURL url; + if (!gtk_util::URLFromPrimarySelection(tabstrip->model_->profile(), &url)) return; TabContents* contents = diff --git a/chrome/browser/gtk/toolbar_star_toggle_gtk.cc b/chrome/browser/gtk/toolbar_star_toggle_gtk.cc deleted file mode 100644 index b688b00..0000000 --- a/chrome/browser/gtk/toolbar_star_toggle_gtk.cc +++ /dev/null @@ -1,141 +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/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<GdkDragAction>(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<GtkThemeProvider*>( - Source<GtkThemeProvider>(source).ptr()); - DCHECK(provider == theme_provider_); - UpdateGTKButton(); -} - -void ToolbarStarToggleGtk::ShowStarBubble(const GURL& url, - bool newly_bookmarked) { - GtkWidget* widget = widget_.get(); - BookmarkBubbleGtk::Show(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 deleted file mode 100644 index faa025a..0000000 --- a/chrome/browser/gtk/toolbar_star_toggle_gtk.h +++ /dev/null @@ -1,76 +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_GTK_TOOLBAR_STAR_TOGGLE_GTK_H_ -#define CHROME_BROWSER_GTK_TOOLBAR_STAR_TOGGLE_GTK_H_ - -#include <gtk/gtk.h> - -#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 a1924fc..1d71dd2 100644 --- a/chrome/browser/location_bar.h +++ b/chrome/browser/location_bar.h @@ -69,6 +69,7 @@ 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 9c8ab48..24747b2 100644 --- a/chrome/browser/net/browser_url_util.cc +++ b/chrome/browser/net/browser_url_util.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -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, false, UnescapeRule::NONE, - NULL, NULL, NULL)); + WideToUTF16(net::FormatUrl(url, languages, net::kFormatUrlOmitNothing, + 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 edacefd..9d974db 100644 --- a/chrome/browser/net/url_fixer_upper.cc +++ b/chrome/browser/net/url_fixer_upper.cc @@ -170,8 +170,9 @@ 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(), true, - UnescapeRule::NORMAL, NULL, NULL, NULL)); + return WideToUTF8(net::FormatUrl(file_url, std::wstring(), + net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, NULL, + NULL, NULL)); } // Invalid file URL, just return the input. @@ -557,7 +558,8 @@ 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(), - true, UnescapeRule::NORMAL, NULL, NULL, NULL)); + net::kFormatUrlOmitUsernamePassword, 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 340f168..fd82db1 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -14,6 +14,7 @@ #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" @@ -47,7 +48,6 @@ #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" @@ -340,8 +340,8 @@ class OffTheRecordProfileImpl : public Profile, return NULL; } - virtual SearchVersusNavigateClassifier* GetSearchVersusNavigateClassifier() { - return profile_->GetSearchVersusNavigateClassifier(); + virtual AutocompleteClassifier* GetAutocompleteClassifier() { + return profile_->GetAutocompleteClassifier(); } virtual WebDataService* GetWebDataService(ServiceAccessType sat) { @@ -1161,13 +1161,10 @@ TemplateURLFetcher* ProfileImpl::GetTemplateURLFetcher() { return template_url_fetcher_.get(); } -SearchVersusNavigateClassifier* -ProfileImpl::GetSearchVersusNavigateClassifier() { - if (!search_versus_navigate_classifier_.get()) { - search_versus_navigate_classifier_.reset( - new SearchVersusNavigateClassifier(this)); - } - return search_versus_navigate_classifier_.get(); +AutocompleteClassifier* ProfileImpl::GetAutocompleteClassifier() { + if (!autocomplete_classifier_.get()) + autocomplete_classifier_.reset(new AutocompleteClassifier(this)); + return autocomplete_classifier_.get(); } WebDataService* ProfileImpl::GetWebDataService(ServiceAccessType sat) { diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index a4f680ad..751d2e2 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -30,6 +30,7 @@ namespace webkit_database { class DatabaseTracker; } +class AutocompleteClassifier; class Blacklist; class BookmarkModel; class BrowserThemeProvider; @@ -55,7 +56,6 @@ class PinnedTabService; class PrefService; class ProfileSyncService; class ProfileSyncFactory; -class SearchVersusNavigateClassifier; class SessionService; class SpellCheckHost; class SSLConfigServiceManager; @@ -217,11 +217,10 @@ class Profile { // doesn't already exist. virtual HistoryService* GetHistoryServiceWithoutCreating() = 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; + // 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; // Returns the WebDataService for this profile. This is owned by // the Profile. Callers that outlive the life of this profile need to be @@ -473,7 +472,7 @@ class ProfileImpl : public Profile, virtual FaviconService* GetFaviconService(ServiceAccessType sat); virtual HistoryService* GetHistoryService(ServiceAccessType sat); virtual HistoryService* GetHistoryServiceWithoutCreating(); - virtual SearchVersusNavigateClassifier* GetSearchVersusNavigateClassifier(); + virtual AutocompleteClassifier* GetAutocompleteClassifier(); virtual WebDataService* GetWebDataService(ServiceAccessType sat); virtual WebDataService* GetWebDataServiceWithoutCreating(); virtual PasswordStore* GetPasswordStore(ServiceAccessType sat); @@ -598,7 +597,7 @@ class ProfileImpl : public Profile, scoped_refptr<DownloadManager> download_manager_; scoped_refptr<HistoryService> history_service_; scoped_refptr<FaviconService> favicon_service_; - scoped_ptr<SearchVersusNavigateClassifier> search_versus_navigate_classifier_; + scoped_ptr<AutocompleteClassifier> autocomplete_classifier_; scoped_refptr<WebDataService> web_data_service_; scoped_refptr<PasswordStore> password_store_; scoped_refptr<SessionService> session_service_; diff --git a/chrome/browser/search_versus_navigate_classifier.cc b/chrome/browser/search_versus_navigate_classifier.cc deleted file mode 100644 index b32b92b..0000000 --- a/chrome/browser/search_versus_navigate_classifier.cc +++ /dev/null @@ -1,56 +0,0 @@ -// 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 deleted file mode 100644 index 94471b8..0000000 --- a/chrome/browser/search_versus_navigate_classifier.h +++ /dev/null @@ -1,52 +0,0 @@ -// 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 <string> - -#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<AutocompleteController> 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 9f83867..5d6ba7b 100644 --- a/chrome/browser/ssl/ssl_browser_tests.cc +++ b/chrome/browser/ssl/ssl_browser_tests.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -65,6 +65,9 @@ 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 c1350e4..7683221 100644 --- a/chrome/browser/ssl/ssl_manager.cc +++ b/chrome/browser/ssl/ssl_manager.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -271,30 +271,15 @@ bool SSLManager::DeserializeSecurityInfo(const std::string& state, } // static -bool SSLManager::GetEVCertNames(const net::X509Certificate& cert, - std::wstring* short_name, - std::wstring* ca_name) { - DCHECK(short_name || ca_name); - +std::wstring SSLManager::GetEVCertName(const net::X509Certificate& cert) { // EV are required to have an organization name and country. if (cert.subject().organization_names.empty() || cert.subject().country_name.empty()) { NOTREACHED(); - return false; + return std::wstring(); } - 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; + return l10n_util::GetStringF(IDS_SECURE_CONNECTION_EV, + UTF8ToWide(cert.subject().organization_names[0]), + UTF8ToWide(cert.subject().country_name)); } diff --git a/chrome/browser/ssl/ssl_manager.h b/chrome/browser/ssl/ssl_manager.h index b0f18e1..f9e1685 100644 --- a/chrome/browser/ssl/ssl_manager.h +++ b/chrome/browser/ssl/ssl_manager.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -92,12 +92,8 @@ class SSLManager : public NotificationObserver { int* cert_status, int* security_bits); - // Sets |short_name| to <organization_name> [<country>] and |ca_name| - // to something like: - // "Verified by <issuer_organization_name>" - static bool GetEVCertNames(const net::X509Certificate& cert, - std::wstring* short_name, - std::wstring* ca_name); + // Returns "<organization_name> [<country>]". + static std::wstring GetEVCertName(const net::X509Certificate& cert); 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 9b4a6e9..7f3ad87 100644 --- a/chrome/browser/ssl/ssl_policy.cc +++ b/chrome/browser/ssl/ssl_policy.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -67,10 +67,9 @@ void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) { handler->ContinueRequest(); break; case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: - // We ignore this error and display an infobar. + // We ignore this error but will show a warning status in the location + // bar. 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: @@ -127,8 +126,12 @@ void SSLPolicy::UpdateEntry(NavigationEntry* entry) { return; } - if (net::IsCertStatusError(entry->ssl().cert_status())) { - entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN); + // 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); return; } diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc index 105e95d..471d2b8 100644 --- a/chrome/browser/tab_contents/render_view_context_menu.cc +++ b/chrome/browser/tab_contents/render_view_context_menu.cc @@ -13,6 +13,7 @@ #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" @@ -27,7 +28,6 @@ #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; - bool is_search; - profile_->GetSearchVersusNavigateClassifier()->Classify( - params_.selection_text, std::wstring(), &is_search, - &selection_navigation_url_, NULL, NULL, NULL); + AutocompleteMatch match; + profile_->GetAutocompleteClassifier()->Classify(params_.selection_text, + std::wstring(), &match, NULL); + selection_navigation_url_ = match.destination_url; if (!selection_navigation_url_.is_valid()) return; @@ -458,7 +458,14 @@ void RenderViewContextMenu::AppendSearchProvider() { i = printable_selection_text.find('&', i + 2)) printable_selection_text.insert(i, 1, '&'); - if (is_search) { + 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 { const TemplateURL* const default_provider = profile_->GetTemplateURLModel()->GetDefaultSearchProvider(); if (!default_provider) @@ -467,13 +474,6 @@ 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 4bd6bd0..6153e75 100644 --- a/chrome/browser/theme_resources_util_unittest.cc +++ b/chrome/browser/theme_resources_util_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -20,7 +20,7 @@ TEST(ThemeResourcesUtil, SpotCheckIds) { const TestCase kTestCases[] = { {"back", IDR_BACK}, {"go", IDR_GO}, - {"star", IDR_STAR}, + {"omnibox_star", IDR_OMNIBOX_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 c651e3d..c641539 100644 --- a/chrome/browser/toolbar_model.cc +++ b/chrome/browser/toolbar_model.cc @@ -17,6 +17,7 @@ #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" @@ -38,7 +39,6 @@ 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,144 +53,70 @@ std::wstring ToolbarModel::GetText() const { url = GURL(url.scheme() + ":"); } } - return net::FormatUrl(url, languages, true, UnescapeRule::NORMAL, NULL, NULL, - NULL); + return net::FormatUrl(url, languages, net::kFormatUrlOmitAll, + UnescapeRule::NORMAL, NULL, NULL, NULL); } ToolbarModel::SecurityLevel ToolbarModel::GetSecurityLevel() const { if (input_in_progress_) // When editing, assume no security style. - return ToolbarModel::NORMAL; + return NONE; NavigationController* navigation_controller = GetNavigationController(); if (!navigation_controller) // We might not have a controller on init. - return ToolbarModel::NORMAL; + return NONE; NavigationEntry* entry = navigation_controller->GetActiveEntry(); if (!entry) - return ToolbarModel::NORMAL; + return NONE; - 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; + const NavigationEntry::SSLStatus& ssl = entry->ssl(); + switch (ssl.security_style()) { case SECURITY_STYLE_UNKNOWN: case SECURITY_STYLE_UNAUTHENTICATED: - return ToolbarModel::NORMAL; - default: - NOTREACHED(); - return ToolbarModel::NORMAL; - } -} - -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; + return NONE; - NavigationEntry* entry = navigation_controller->GetActiveEntry(); - if (!entry) - return ToolbarModel::NO_ICON; + case SECURITY_STYLE_AUTHENTICATION_BROKEN: + return SECURITY_ERROR; - const NavigationEntry::SSLStatus& ssl = entry->ssl(); - switch (ssl.security_style()) { case SECURITY_STYLE_AUTHENTICATED: if (ssl.has_mixed_content()) - 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; + 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; + default: NOTREACHED(); - return ToolbarModel::NO_ICON; + return NONE; } } -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; - } +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()]; } -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; - +std::wstring ToolbarModel::GetEVCertName() const { + DCHECK_EQ(GetSecurityLevel(), EV_SECURE); scoped_refptr<net::X509Certificate> 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; + // 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); } NavigationController* ToolbarModel::GetNavigationController() const { @@ -200,37 +126,3 @@ 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<SSLErrorInfo> 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<int>(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 1d959c5..a4959e6fd 100644 --- a/chrome/browser/toolbar_model.h +++ b/chrome/browser/toolbar_model.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -18,54 +18,36 @@ 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 { - SECURE = 0, - NORMAL, - INSECURE - }; - - enum Icon { - NO_ICON = 0, - LOCK_ICON, - WARNING_ICON - }; - - enum InfoTextType { - INFO_NO_INFO = 0, - INFO_EV_TEXT, + 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, }; 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 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 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 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; + // Returns the name of the EV cert holder. Only call this when the security + // level is EV_SECURE. + std::wstring GetEVCertName() const; // Getter/setter of whether the text in location bar is currently being // edited. @@ -78,10 +60,6 @@ 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 c8b54f7..9e1f6c9 100644 --- a/chrome/browser/views/accelerator_table_gtk.cc +++ b/chrome/browser/views/accelerator_table_gtk.cc @@ -115,7 +115,6 @@ 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 }, @@ -129,7 +128,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_MANAGER }, + { base::VKEY_B, true, true, false, IDC_SHOW_BOOKMARK_BAR }, #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 b5fc226..7cea6af 100644 --- a/chrome/browser/views/app_launcher.cc +++ b/chrome/browser/views/app_launcher.cc @@ -16,12 +16,13 @@ #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" @@ -45,10 +46,11 @@ const int kNavigationEntryYMargin = 1; // Padding between the navigation bar and the render view contents. const int kNavigationBarBottomPadding = 3; -// NavigationBar size. -const int kNavigationBarHeight = 25; +// NavigationBar constants. +const int kNavigationBarHeight = 23; +const int kNavigationBarBorderThickness = 1; -// 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,8 +76,7 @@ static GURL GetMenuURL() { // mode. class NavigationBar : public views::View, - public AutocompleteEditController, - public BubblePositioner { + public AutocompleteEditController { public: explicit NavigationBar(AppLauncher* app_launcher) : app_launcher_(app_launcher), @@ -83,7 +84,12 @@ class NavigationBar : public views::View, SetFocusable(true); location_entry_view_ = new views::NativeViewHost; AddChildView(location_entry_view_); - set_border(views::Border::CreateSolidBorder(1, SK_ColorGRAY)); + set_border(views::Border::CreateSolidBorder(kNavigationBarBorderThickness, + SK_ColorGRAY)); + + AddChildView(&popup_positioning_view_); + popup_positioning_view_.SetVisible(false); + popup_positioning_view_.set_parent_owned(false); } virtual ~NavigationBar() { @@ -113,7 +119,8 @@ class NavigationBar : public views::View, new AutocompleteEditViewWin(font, this, browser->toolbar_model(), this, GetWidget()->GetNativeView(), browser->profile(), - browser->command_updater(), false, this); + browser->command_updater(), false, + &popup_positioning_view_); location_entry_.reset(autocomplete_view); autocomplete_view->Update(NULL); // The Update call above sets the autocomplete text to the current one in @@ -123,10 +130,11 @@ class NavigationBar : public views::View, AutocompleteEditViewGtk* autocomplete_view = new AutocompleteEditViewGtk(this, browser->toolbar_model(), browser->profile(), - browser->command_updater(), false, this); + browser->command_updater(), false, + &popup_positioning_view_); autocomplete_view->Init(); - gtk_widget_show_all(autocomplete_view->widget()); - gtk_widget_hide(autocomplete_view->widget()); + gtk_widget_show_all(autocomplete_view->GetNativeView()); + gtk_widget_hide(autocomplete_view->GetNativeView()); location_entry_.reset(autocomplete_view); #else NOTIMPLEMENTED(); @@ -143,21 +151,10 @@ class NavigationBar : public views::View, bounds.width() - 2 * (kNavigationEntryPadding + kNavigationEntryXMargin), bounds.height() - kNavigationEntryYMargin * 2); - } - // 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; + gfx::Rect popup_positioning_bounds(bounds); + popup_positioning_bounds.Inset(0, -(kNavigationBarBorderThickness + 1)); + popup_positioning_view_.SetBounds(popup_positioning_bounds); } // AutocompleteController implementation. @@ -197,6 +194,11 @@ 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,6 +241,7 @@ InfoBubbleContentsView::InfoBubbleContentsView(AppLauncher* app_launcher) : app_launcher_(app_launcher), navigation_bar_(NULL), dom_view_(NULL) { + DCHECK(app_launcher); } InfoBubbleContentsView::~InfoBubbleContentsView() { @@ -301,6 +304,7 @@ void InfoBubbleContentsView::Layout() { AppLauncher::AppLauncher(Browser* browser) : browser_(browser), info_bubble_(NULL) { + DCHECK(browser); info_bubble_content_ = new InfoBubbleContentsView(this); } @@ -308,12 +312,15 @@ AppLauncher::~AppLauncher() { } // static -AppLauncher* AppLauncher::Show(Browser* browser, const gfx::Rect& bounds) { +AppLauncher* AppLauncher::Show(Browser* browser, + const gfx::Rect& bounds, + const gfx::Point& bubble_anchor) { AppLauncher* app_launcher = new AppLauncher(browser); BrowserView* browser_view = static_cast<BrowserView*>(browser->window()); app_launcher->info_bubble_ = - InfoBubble::Show(browser_view->frame()->GetWindow(), bounds, - app_launcher->info_bubble_content_, app_launcher); + PinnedContentsInfoBubble::Show(browser_view->frame()->GetWindow(), + bounds, bubble_anchor, app_launcher->info_bubble_content_, + app_launcher); app_launcher->info_bubble_content_->BubbleShown(); return app_launcher; } @@ -328,7 +335,17 @@ AppLauncher* AppLauncher::ShowForNewTab(Browser* browser) { gfx::Point origin = bounds.origin(); views::RootView::ConvertPointToScreen(tabstrip, &origin); bounds.set_origin(origin); - return Show(browser, bounds); + + // 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); } void AppLauncher::Hide() { @@ -368,7 +385,6 @@ void AppLauncher::InfoBubbleClosing(InfoBubble* info_bubble, new DeleteTask<AppLauncher>(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 bd18cfb..1472f06 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/info_bubble.h" +#include "chrome/browser/views/pinned_contents_info_bubble.h" #include "views/view.h" class Browser; @@ -39,13 +39,17 @@ 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). + // be in screen coordinates). |bubble_anchor| specifies at which coordinates + // the bubble contents should appear (in screen coordinates). The bubble will + // be moved accordingly. // 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); + static AppLauncher* Show(Browser* browser, + const gfx::Rect& bounds, + const gfx::Point& bubble_anchor); // Shows an application launcher bubble pointing to the new tab button. // The caller DOES NOT OWN the AppLauncher returned. It is deleted @@ -97,8 +101,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. - InfoBubble* info_bubble_; + // The InfoBubble displaying the Omnibox and app contents. + PinnedContentsInfoBubble* 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 d5eb1f3..de0464e 100644 --- a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc +++ b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc @@ -12,7 +12,6 @@ #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" @@ -91,13 +90,8 @@ const int kIconVerticalPadding = 2; // bottom of the row. See comment about the use of "minimum" for // kIconVerticalPadding. const int kTextVerticalPadding = 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 padding between horizontally adjacent items (including row edges). +const int kHorizontalPadding = 3; // The size delta between the font used for the edit and the result rows. Passed // to gfx::Font::DeriveFont. #if !defined(OS_CHROMEOS) @@ -170,40 +164,15 @@ 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 @@ -322,7 +291,11 @@ AutocompleteResultView::AutocompleteResultView( mirroring_context_(new MirroringContext()), match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED) { CHECK(model_index >= 0); - InitClass(); + if (icon_size_ == 0) { + icon_size_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( + AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))-> + width(); + } } AutocompleteResultView::~AutocompleteResultView() { @@ -344,7 +317,8 @@ 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 - kIconTextSpacing : text_bounds_.right(); + int text_right = + text_mirroring ? (x - kHorizontalPadding) : 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()); @@ -365,13 +339,11 @@ void AutocompleteResultView::Paint(gfx::Canvas* canvas) { } void AutocompleteResultView::Layout() { - icon_bounds_.SetRect(kRowLeftPadding, (height() - icon_size_) / 2, + icon_bounds_.SetRect(kHorizontalPadding, (height() - icon_size_) / 2, icon_size_, icon_size_); - 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), + 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), font_.height()); } @@ -389,29 +361,19 @@ ResultViewState AutocompleteResultView::GetState() const { } SkBitmap* AutocompleteResultView::GetIcon() const { - 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; + 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; + } } + return ResourceBundle::GetSharedInstance().GetBitmapNamed(icon); } int AutocompleteResultView::DrawString( @@ -508,7 +470,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() - kRowRightPadding - x); + width() - kHorizontalPadding - x); int string_left = mirroring_context_->GetLeft(x, x + string_width); const int flags = force_rtl_directionality ? gfx::Canvas::FORCE_RTL_DIRECTIONALITY : 0; @@ -531,25 +493,6 @@ 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: @@ -558,10 +501,10 @@ AutocompletePopupContentsView::AutocompletePopupContentsView( AutocompleteEditView* edit_view, AutocompleteEditModel* edit_model, Profile* profile, - const BubblePositioner* bubble_positioner) + const views::View* location_bar) : model_(new AutocompletePopupModel(this, edit_model, profile)), edit_view_(edit_view), - bubble_positioner_(bubble_positioner), + location_bar_(location_bar), result_font_(font.DeriveFont(kEditFontAdjust)), ignore_mouse_drag_(false), ALLOW_THIS_IN_INITIALIZER_LIST(size_animation_(this)) { @@ -637,10 +580,13 @@ void AutocompletePopupContentsView::UpdatePopupAppearance() { } // Calculate desired bounds. - 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))); + 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))); // 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 @@ -847,7 +793,19 @@ void AutocompletePopupContentsView::MakeContentsPath( SkIntToScalar(bounding_rect.bottom())); SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius()); - path->addRoundRect(rect, radius, radius); + 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(); } void AutocompletePopupContentsView::UpdateBlurRegion() { @@ -920,14 +878,3 @@ 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 30a9bf1..d814206 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 BubblePositioner* bubble_positioner); + const views::View* location_bar); 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 tells the popup how to position itself. - const BubblePositioner* bubble_positioner_; + // An object that the popup positions itself against. + const views::View* location_bar_; // 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 34f8e91..bd61ab3 100644 --- a/chrome/browser/views/bookmark_editor_view.cc +++ b/chrome/browser/views/bookmark_editor_view.cc @@ -282,10 +282,9 @@ void BookmarkEditorView::Init() { std::wstring languages = profile_ ? profile_->GetPrefs()->GetString(prefs::kAcceptLanguages) : std::wstring(); - // The following URL is user-editable. We specify omit_username_password= - // false and unescape=false to show the original URL except IDN. + // The following URL is user-editable, so we don't strip anything from it. url_text = net::FormatUrl(details_.existing_node->GetURL(), languages, - false, UnescapeRule::NONE, NULL, NULL, NULL); + net::kFormatUrlOmitNothing, 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 ac20277..6a5bcf1 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) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -218,7 +218,8 @@ 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 230a0f4..3548286 100644 --- a/chrome/browser/views/bubble_border.cc +++ b/chrome/browser/views/bubble_border.cc @@ -1,6 +1,6 @@ -// 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. +// 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/bubble_border.h" @@ -31,10 +31,6 @@ 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; @@ -43,33 +39,40 @@ 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_x_offset_; + x -= arrow_offset; else if (arrow_location_ == NONE) x -= ((contents_size.width() / 2) + insets.left()); else - x += (arrow_x_offset_ - border_size.width() + 1); + x += (arrow_offset - border_size.width() + 1); int y = position_relative_to.y(); - 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()); - } + 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); return gfx::Rect(x, y, border_size.width(), border_size.height()); } void BubbleBorder::GetInsets(gfx::Insets* insets) const { - 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()); + 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(); + } insets->Set(top, left_->width(), bottom, right_->width()); } @@ -102,7 +105,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(); @@ -132,25 +135,33 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { * border_bottom∙∙∙∙└────┴─┤ â–¼ ├──────┤ â–¼ ├─┴────┘ * view.height()∙∙∙∙∙∙∙∙∙∙∙└───┘ └───┘ * - * (At most one of the arrows will be drawn) + * 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. */ 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; - // Top left corner - canvas->DrawBitmapInt(*top_left_, 0, border_top); + 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 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, @@ -167,7 +178,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 = true; + bool should_draw_top_edge = false; bool should_draw_bottom_edge = true; if (arrow_location_ != NONE) { /* Here's what the variables below mean (without loss of generality): @@ -194,17 +205,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_top()) { - should_draw_top_edge = false; - edge = top_; - arrow = top_arrow_; - left_of_edge = tl_width; - right_of_edge = tr_width; - edge_y = border_top; - arrow_y = top - top_arrow_->height(); - border_y = SkIntToScalar(top); - tip_y = SkIntToScalar(top - kArrowInteriorHeight); - } else { + if (arrow_is_bottom()) { + should_draw_top_edge = true; should_draw_bottom_edge = false; edge = bottom_; arrow = bottom_arrow_; @@ -213,10 +215,21 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { edge_y = arrow_y = bottom; border_y = SkIntToScalar(bottom); tip_y = SkIntToScalar(bottom + kArrowInteriorHeight); + } else { + edge = top_; + arrow = top_arrow_; + left_of_edge = tl_width; + right_of_edge = tr_width; + edge_y = border_top; + arrow_y = top - top_arrow_->height(); + border_y = SkIntToScalar(top); + tip_y = SkIntToScalar(top - kArrowInteriorHeight); } - int arrow_width = (arrow_is_top() ? top_arrow_ : bottom_arrow_)->width(); + int arrow_offset = override_arrow_x_offset_ ? override_arrow_x_offset_ : + arrow_x_offset_; + int arrow_width = arrow->width(); int arrow_center = arrow_is_left() ? - arrow_x_offset_ : width - arrow_x_offset_ - 1; + arrow_offset : width - arrow_offset - 1; int arrow_x = arrow_center - (arrow_width / 2); SkScalar arrow_interior_x = SkIntToScalar(arrow_center - kArrowInteriorHeight); @@ -271,6 +284,8 @@ 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 3b48048..3670503 100644 --- a/chrome/browser/views/bubble_border.h +++ b/chrome/browser/views/bubble_border.h @@ -1,6 +1,6 @@ -// 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. +// 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_BUBBLE_BORDER_H_ #define CHROME_BROWSER_VIEWS_BUBBLE_BORDER_H_ @@ -11,8 +11,11 @@ class SkBitmap; -// Renders a round-rect border, with optional arrow (off by default), and a -// custom dropshadow. This can be used to produce floating "bubble" objects. +// 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. class BubbleBorder : public views::Border { public: // Possible locations for the (optional) arrow. @@ -24,7 +27,9 @@ class BubbleBorder : public views::Border { BOTTOM_RIGHT }; - BubbleBorder() : arrow_location_(NONE), background_color_(SK_ColorWHITE) { + BubbleBorder() : override_arrow_x_offset_(0), + arrow_location_(NONE), + background_color_(SK_ColorWHITE) { InitClass(); } @@ -42,6 +47,12 @@ 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) { @@ -68,9 +79,10 @@ class BubbleBorder : public views::Border { virtual ~BubbleBorder() { } - // 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 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 left side. @@ -95,6 +107,9 @@ 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 488f1a4..c70ec75 100644 --- a/chrome/browser/views/constrained_window_win.cc +++ b/chrome/browser/views/constrained_window_win.cc @@ -34,6 +34,7 @@ #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; @@ -349,24 +350,7 @@ int ConstrainedWindowFrameView::NonClientHitTest(const gfx::Point& point) { void ConstrainedWindowFrameView::GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) { DCHECK(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(); + views::GetDefaultWindowMask(size, window_mask); } 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 d12963f..0092fa7 100644 --- a/chrome/browser/views/frame/browser_frame_win.cc +++ b/chrome/browser/views/frame/browser_frame_win.cc @@ -28,6 +28,9 @@ // 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, @@ -303,7 +306,8 @@ void BrowserFrameWin::UpdateDWMFrame() { margins.cyTopHeight += GetSystemMetrics(SM_CYSIZEFRAME); } else { margins.cyTopHeight = - GetBoundsForTabStrip(browser_view_->tabstrip()).bottom(); + GetBoundsForTabStrip(browser_view_->tabstrip()).bottom() + + kDWMFrameTopOffset; } } } else { diff --git a/chrome/browser/views/frame/browser_root_view.cc b/chrome/browser/views/frame/browser_root_view.cc index d789b94..d2985dd 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) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -7,9 +7,10 @@ #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" @@ -141,13 +142,13 @@ bool BrowserRootView::GetPasteAndGoURL(const OSExchangeData& data, GURL* url) { if (!data.GetString(&text) || text.empty()) return false; - GURL destination_url; - browser_view_->browser()->profile()->GetSearchVersusNavigateClassifier()-> - Classify(text, std::wstring(), NULL, &destination_url, NULL, NULL, NULL); - if (!destination_url.is_valid()) + AutocompleteMatch match; + browser_view_->browser()->profile()->GetAutocompleteClassifier()->Classify( + text, std::wstring(), &match, NULL); + if (!match.destination_url.is_valid()) return false; if (url) - *url = destination_url; + *url = match.destination_url; return true; } diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index 732a1fb..614659e 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -8,20 +8,13 @@ #include <gtk/gtk.h> #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" @@ -30,40 +23,30 @@ #include "chrome/browser/ntp_background_util.h" #include "chrome/browser/page_info_window.h" #include "chrome/browser/pref_service.h" -#include "chrome/browser/profile.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/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_view_layout.h" #include "chrome/browser/views/frame/browser_extender.h" -#include "chrome/browser/views/frame/browser_frame.h" +#include "chrome/browser/views/frame/browser_view_layout.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" @@ -71,14 +54,11 @@ #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) @@ -789,7 +769,7 @@ void BrowserView::UpdateLoadingAnimations(bool should_animate) { } void BrowserView::SetStarredState(bool is_starred) { - toolbar_->star_button()->SetToggled(is_starred); + toolbar_->location_bar()->SetStarToggled(is_starred); } gfx::Rect BrowserView::GetRestoredBounds() const { @@ -969,7 +949,7 @@ void BrowserView::ShowBookmarkManager() { } void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) { - toolbar_->star_button()->ShowStarBubble(url, !already_bookmarked); + toolbar_->location_bar()->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 608fea9..9a665f7 100644 --- a/chrome/browser/views/frame/glass_browser_frame_view.cc +++ b/chrome/browser/views/frame/glass_browser_frame_view.cc @@ -40,6 +40,8 @@ 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; @@ -261,19 +263,46 @@ void GlassBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) { toolbar_bounds.x() - 1, toolbar_bounds.y() + 2, toolbar_bounds.width() + 2, theme_toolbar->height()); - SkBitmap* toolbar_left = - tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER); - canvas->DrawBitmapInt(*toolbar_left, - toolbar_bounds.x() - toolbar_left->width(), - toolbar_bounds.y()); - + // 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_center = tp->GetBitmapNamed(IDR_CONTENT_TOP_CENTER); - canvas->TileImageInt(*toolbar_center, toolbar_bounds.x(), toolbar_bounds.y(), - toolbar_bounds.width(), toolbar_center->height()); + canvas->TileImageInt(*toolbar_center, left_x + toolbar_left->width(), + toolbar_bounds.y(), + right_x - (left_x + toolbar_left->width()), + toolbar_center->height()); + // Right edge. canvas->DrawBitmapInt(*tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER), - toolbar_bounds.right(), toolbar_bounds.y()); + right_x, 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 e9276f8..c91cb51 100644 --- a/chrome/browser/views/frame/opaque_browser_frame_view.cc +++ b/chrome/browser/views/frame/opaque_browser_frame_view.cc @@ -26,6 +26,7 @@ #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" @@ -58,6 +59,8 @@ 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. @@ -89,6 +92,9 @@ 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; } /////////////////////////////////////////////////////////////////////////////// @@ -188,7 +194,7 @@ gfx::Rect OpaqueBrowserFrameView::GetBoundsForTabStrip( BaseTabStrip* tabstrip) const { int tabstrip_x = browser_view_->ShouldShowOffTheRecordAvatar() ? (otr_avatar_icon_->bounds().right() + kOTRSideSpacing) : - NonClientBorderThickness(); + NonClientBorderThickness() + kTabStripIndent; int tabstrip_width = minimize_button_->x() - tabstrip_x - (frame_->GetWindow()->IsMaximized() ? kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing); @@ -298,23 +304,7 @@ void OpaqueBrowserFrameView::GetWindowMask(const gfx::Size& size, if (frame_->GetWindow()->IsMaximized() || frame_->GetWindow()->IsFullscreen()) return; - // 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(); + views::GetDefaultWindowMask(size, window_mask); } void OpaqueBrowserFrameView::EnableClose(bool enable) { @@ -717,6 +707,17 @@ 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, @@ -732,26 +733,65 @@ 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, - toolbar_bounds.x() - toolbar_left->width(), toolbar_bounds.y(), + left_x, 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, toolbar_bounds.x() - toolbar_left->width(), bottom_y, + bottom_edge_height, left_x, bottom_y, toolbar_left->width(), bottom_edge_height, false); SkBitmap* toolbar_center = tp->GetBitmapNamed(IDR_CONTENT_TOP_CENTER); - canvas->TileImageInt(*toolbar_center, 0, 0, toolbar_bounds.x(), - toolbar_bounds.y(), toolbar_bounds.width(), split_point); + canvas->TileImageInt(*toolbar_center, 0, 0, left_x + toolbar_left->width(), + toolbar_bounds.y(), right_x - (left_x + toolbar_left->width()), + split_point); SkBitmap* toolbar_right = tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER); canvas->DrawBitmapInt(*toolbar_right, 0, 0, toolbar_right->width(), - split_point, toolbar_bounds.right(), toolbar_bounds.y(), + split_point, right_x, 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, toolbar_bounds.right(), bottom_y, + bottom_edge_height, right_x, 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 e5c4858..8150db9 100644 --- a/chrome/browser/views/info_bubble.cc +++ b/chrome/browser/views/info_bubble.cc @@ -29,55 +29,17 @@ 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. - BubbleBorder* bubble_border = new BubbleBorder; - set_border(bubble_border); - bubble_border->set_background_color(InfoBubble::kBackgroundColor); + if (!bubble_border_) + 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); @@ -88,9 +50,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<WindowSizer::MonitorInfoProvider> monitor_provider( @@ -109,10 +71,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); } @@ -120,7 +82,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); } @@ -128,6 +90,8 @@ 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); @@ -150,7 +114,7 @@ void BorderContents::Paint(gfx::Canvas* canvas) { #if defined(OS_WIN) // BorderWidget --------------------------------------------------------------- -BorderWidget::BorderWidget() { +BorderWidget::BorderWidget() : border_contents_(NULL) { 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); @@ -163,15 +127,16 @@ gfx::Rect BorderWidget::InitAndGetBounds( bool prefer_arrow_on_right) { // Set up the border view and ask it to calculate our bounds (and our // contents'). - BorderContents* border_contents = new BorderContents; + if (!border_contents_) + 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); @@ -268,7 +233,8 @@ void InfoBubble::Init(views::Window* parent, (contents->UILayoutIsRightToLeft() == delegate->PreferOriginSideAnchor()); #if defined(OS_WIN) - border_.reset(new BorderWidget); + if (!border_.get()) + 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 90911b5..ea80b0f 100644 --- a/chrome/browser/views/info_bubble.h +++ b/chrome/browser/views/info_bubble.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -7,6 +7,7 @@ #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) @@ -23,6 +24,7 @@ // have any additional margins. class BorderWidget; +class BubbleBorder; class InfoBubble; namespace views { @@ -33,6 +35,46 @@ 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 @@ -47,12 +89,15 @@ 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. - gfx::Rect InitAndGetBounds(HWND owner, - const gfx::Rect& position_relative_to, - const gfx::Size& contents_size, - bool is_rtl); + virtual gfx::Rect InitAndGetBounds(HWND owner, + const gfx::Rect& position_relative_to, + const gfx::Size& contents_size, + bool is_rtl); + + protected: + BorderContents* border_contents_; private: // Overridden from WidgetWin: @@ -82,7 +127,7 @@ class InfoBubbleDelegate { virtual bool PreferOriginSideAnchor() { return true; } }; -// TODO: this code is ifdef-tastic. It might be cleaner to refactor the +// TODO(sky): 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 @@ -120,10 +165,10 @@ class InfoBubble virtual ~InfoBubble() {} // Creates the InfoBubble. - void Init(views::Window* parent, - const gfx::Rect& position_relative_to, - views::View* contents, - InfoBubbleDelegate* delegate); + virtual void Init(views::Window* parent, + const gfx::Rect& position_relative_to, + views::View* contents, + InfoBubbleDelegate* delegate); #if defined(OS_WIN) // Overridden from WidgetWin: @@ -133,6 +178,11 @@ class InfoBubble virtual void IsActiveChanged(); #endif +#if defined(OS_WIN) + // The window used to render the padding, border and arrow. + scoped_ptr<BorderWidget> border_; +#endif + private: // Closes the window notifying the delegate. |closed_by_escape| is true if // the close is the result of pressing escape. @@ -147,11 +197,6 @@ 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<BorderWidget> 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 7a1e4d9..935598c 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -8,6 +8,7 @@ #include <gtk/gtk.h> #endif +#include "app/drag_drop_types.h" #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "app/theme_provider.h" @@ -16,8 +17,6 @@ #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" @@ -26,17 +25,15 @@ #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/view_ids.h" -#include "chrome/browser/views/extensions/extension_popup.h" -#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/browser_dialogs.h" #include "chrome/browser/views/content_blocked_bubble_contents.h" -#include "chrome/common/content_settings.h" +#include "chrome/browser/views/frame/browser_view.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 "net/base/net_util.h" +#include "views/drag_utils.h" #if defined(OS_WIN) #include "chrome/browser/views/first_run_bubble.h" @@ -47,20 +44,31 @@ using views::View; // static const int LocationBarView::kVertMargin = 2; -// Padding on the right and left of the entry field. -static const int kEntryPadding = 3; +// 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 between the entry and the leading/trailing views. -static const int kInnerPadding = 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, +}; 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; @@ -132,21 +140,23 @@ LocationBarView::LocationBarView(Profile* profile, CommandUpdater* command_updater, ToolbarModel* model, Delegate* delegate, - bool popup_window_mode, - const BubblePositioner* bubble_positioner) + bool popup_window_mode) : 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_(profile), + selected_keyword_view_(kSelectedKeywordBackgroundImages, + IDR_OMNIBOX_SEARCH, SK_ColorBLACK, profile), keyword_hint_view_(profile), - type_to_search_view_(l10n_util::GetString(IDS_OMNIBOX_EMPTY_TEXT)), - security_image_view_(this, profile, model, bubble_positioner), + star_view_(command_updater), popup_window_mode_(popup_window_mode), - first_run_bubble_(this), - bubble_positioner_(bubble_positioner) { + ALLOW_THIS_IN_INITIALIZER_LIST(first_run_bubble_(this)) { DCHECK(profile_); SetID(VIEW_ID_LOCATION_BAR); SetFocusable(true); @@ -170,52 +180,45 @@ 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, - widget->GetNativeView(), - profile_, command_updater_, - popup_window_mode_, - bubble_positioner_)); + GetWidget()->GetNativeView(), profile_, command_updater_, + popup_window_mode_, this)); #else location_entry_.reset(new AutocompleteEditViewGtk(this, model_, profile_, - command_updater_, - popup_window_mode_, - bubble_positioner_)); + command_updater_, popup_window_mode_, this)); 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_->widget()); + gtk_widget_show_all(location_entry_->GetNativeView()); // Hide the widget. NativeViewHostGtk will make it visible again as // necessary. - gtk_widget_hide(location_entry_->widget()); + gtk_widget_hide(location_entry_->GetNativeView()); #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( -#if defined(OS_WIN) - location_entry_->m_hWnd -#else - location_entry_->widget() -#endif - ); // NOLINT + location_entry_view_->Attach(location_entry_->GetNativeView()); 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(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); + SkColor dimmed_text = GetColor(ToolbarModel::NONE, DEEMPHASIZED_TEXT); AddChildView(&keyword_hint_view_); keyword_hint_view_.SetVisible(false); @@ -223,22 +226,19 @@ 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<ContentSettingsType>(i), this, - profile_, bubble_positioner_); + ContentSettingImageView* content_blocked_view = new ContentSettingImageView( + static_cast<ContentSettingsType>(i), this, profile_); content_setting_views_.push_back(content_blocked_view); AddChildView(content_blocked_view); content_blocked_view->SetVisible(false); } - AddChildView(&info_label_); - info_label_.SetVisible(false); - info_label_.set_parent_owned(false); + if (!popup_window_mode_) { + AddChildView(&star_view_); + star_view_.SetVisible(true); + star_view_.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,63 +256,59 @@ bool LocationBarView::IsInitialized() const { } // static -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) { +SkColor LocationBarView::GetColor(ToolbarModel::SecurityLevel security_level, + ColorKind kind) { + switch (kind) { #if defined(OS_WIN) - 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); + 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); #else // TODO(beng): source from theme provider. - colors[NOT_SECURE][BACKGROUND] = SK_ColorWHITE; - colors[NOT_SECURE][TEXT] = SK_ColorBLACK; - colors[NOT_SECURE][SELECTED_TEXT] = SK_ColorWHITE; + case BACKGROUND: return SK_ColorWHITE; + case TEXT: return SK_ColorBLACK; + case SELECTED_TEXT: return SK_ColorWHITE; #endif - 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]; + 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); + } } 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); - Layout(); - SchedulePaint(); + OnChanged(); } void LocationBarView::UpdateContentSettingsIcons() { @@ -362,7 +358,6 @@ 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); } } @@ -370,8 +365,11 @@ 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(); @@ -400,13 +398,156 @@ 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() { - DoLayout(true); + 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); } void LocationBarView::Paint(gfx::Canvas* canvas) { @@ -419,10 +560,9 @@ void LocationBarView::Paint(gfx::Canvas* canvas) { canvas->TileImageInt(*background, 0, 0, 0, 0, width(), height()); int top_margin = TopMargin(); - canvas->FillRectInt( - GetColor(model_->GetSchemeSecurityLevel() == ToolbarModel::SECURE, - BACKGROUND), - 0, top_margin, width(), std::max(height() - top_margin - kVertMargin, 0)); + canvas->FillRectInt(GetColor(ToolbarModel::NONE, BACKGROUND), 0, + top_margin, width(), + std::max(height() - top_margin - kVertMargin, 0)); } void LocationBarView::VisibleBoundsInRootChanged() { @@ -509,7 +649,11 @@ void LocationBarView::OnAutocompleteAccept( } void LocationBarView::OnChanged() { - DoLayout(false); + location_icon_view_.SetImage( + ResourceBundle::GetSharedInstance().GetBitmapNamed( + location_entry_->GetIcon())); + Layout(); + SchedulePaint(); } void LocationBarView::OnInputInProgress(bool in_progress) { @@ -540,117 +684,6 @@ 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()); } @@ -669,52 +702,7 @@ int LocationBarView::AvailableWidth(int location_bar_width) { } bool LocationBarView::UsePref(int pref_width, int 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; + return (pref_width + kViewPadding <= available_width); } void LocationBarView::LayoutView(bool leading, @@ -725,40 +713,20 @@ 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() + 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 { + if (view_size.width() + kViewPadding >= bounds->width()) { view->SetVisible(false); + return; } -} - -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; + 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()); } + bounds->set_width(bounds->width() - view_size.width() - kViewPadding); + view->SetVisible(true); } void LocationBarView::RefreshContentSettingViews() { @@ -778,7 +746,9 @@ void LocationBarView::DeletePageActionViews() { } void LocationBarView::RefreshPageActionViews() { - std::vector<ExtensionAction*> page_actions; + if (popup_window_mode_) + return; + ExtensionsService* service = profile_->GetExtensionsService(); if (!service) return; @@ -790,6 +760,7 @@ void LocationBarView::RefreshPageActionViews() { // Remember the previous visibility of the page actions so that we can // notify when this changes. + std::vector<ExtensionAction*> 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()); @@ -804,8 +775,7 @@ 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], bubble_positioner_)); + new PageActionImageView(this, profile_, page_actions[i])); page_action_views_[i]->SetVisible(false); AddChildView(page_action_views_[i]); } @@ -832,25 +802,6 @@ 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; @@ -867,11 +818,55 @@ 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 +} + +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); @@ -879,76 +874,213 @@ bool LocationBarView::GetAccessibleRole(AccessibilityTypes::Role* role) { return true; } -// SelectedKeywordView ------------------------------------------------------- -// 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::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; +} -// Insets around the label. -static const int kTopInset = 0; -static const int kBottomInset = 0; -static const int kLeftInset = 4; -static const int kRightInset = 4; +void LocationBarView::EVBubbleView::OnMouseReleased( + const views::MouseEvent& event, + bool canceled) { + click_handler_.OnMouseReleased(event, canceled); +} -// Offset from the top the background is drawn at. -static const int kBackgroundYOffset = 2; +// SelectedKeywordView --------------------------------------------------------- -LocationBarView::SelectedKeywordView::SelectedKeywordView(Profile* profile) - : background_painter_(kBorderImages), +LocationBarView::SelectedKeywordView::SelectedKeywordView( + const int background_images[], + int contained_image, + const SkColor& color, + Profile* profile) + : IconLabelBubbleView(background_images, contained_image, color), 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() { - return full_label_.GetPreferredSize(); + gfx::Size size(GetNonLabelSize()); + size.Enlarge(full_label_.GetPreferredSize().width(), 0); + return size; } gfx::Size LocationBarView::SelectedKeywordView::GetMinimumSize() { - return partial_label_.GetMinimumSize(); + gfx::Size size(GetNonLabelSize()); + size.Enlarge(partial_label_.GetMinimumSize().width(), 0); + return size; } void LocationBarView::SelectedKeywordView::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); + SetLabel((width() == GetPreferredSize().width()) ? + full_label_.GetText() : partial_label_.GetText()); + IconLabelBubbleView::Layout(); } void LocationBarView::SelectedKeywordView::SetKeyword( @@ -964,12 +1096,9 @@ void LocationBarView::SelectedKeywordView::SetKeyword( full_label_.SetText(l10n_util::GetStringF(IDS_OMNIBOX_KEYWORD_TEXT, short_name)); const std::wstring min_string = CalculateMinString(short_name); - if (!min_string.empty()) { - partial_label_.SetText( - l10n_util::GetStringF(IDS_OMNIBOX_KEYWORD_TEXT, min_string)); - } else { - partial_label_.SetText(full_label_.GetText()); - } + partial_label_.SetText(min_string.empty() ? + full_label_.GetText() : + l10n_util::GetStringF(IDS_OMNIBOX_KEYWORD_TEXT, min_string)); } std::wstring LocationBarView::SelectedKeywordView::CalculateMinString( @@ -1096,250 +1225,18 @@ 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, - const BubblePositioner* bubble_positioner) + Profile* profile) : content_setting_image_model_( ContentSettingImageModel::CreateContentSettingImageModel( content_type)), parent_(parent), profile_(profile), - info_bubble_(NULL), - bubble_positioner_(bubble_positioner) { + info_bubble_(NULL) { } LocationBarView::ContentSettingImageView::~ContentSettingImageView() { @@ -1351,29 +1248,39 @@ 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 (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 { + if (!content_setting_image_model_->is_visible()) { 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) { - gfx::Rect bounds(bubble_positioner_->GetLocationStackBounds()); - gfx::Point location; - views::View::ConvertPointToScreen(this, &location); - bounds.set_x(location.x()); - bounds.set_width(width()); + // 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; TabContents* tab_contents = parent_->GetTabContents(); if (!tab_contents) - return true; + return; + + gfx::Rect screen_bounds(GetImageBounds()); + gfx::Point origin(screen_bounds.origin()); + views::View::ConvertPointToScreen(this, &origin); + screen_bounds.set_origin(origin); ContentSettingBubbleContents* bubble_contents = new ContentSettingBubbleContents( ContentSettingBubbleModel::CreateContentSettingBubbleModel( @@ -1381,9 +1288,9 @@ bool LocationBarView::ContentSettingImageView::OnMousePressed( content_setting_image_model_->get_content_settings_type()), profile_, tab_contents); DCHECK(!info_bubble_); - info_bubble_ = InfoBubble::Show(GetWindow(), bounds, bubble_contents, this); + info_bubble_ = + InfoBubble::Show(GetWindow(), screen_bounds, bubble_contents, this); bubble_contents->set_info_bubble(info_bubble_); - return true; } void LocationBarView::ContentSettingImageView::VisibilityChanged( @@ -1408,10 +1315,8 @@ bool LocationBarView::ContentSettingImageView::CloseOnEscape() { LocationBarView::PageActionImageView::PageActionImageView( LocationBarView* owner, Profile* profile, - ExtensionAction* page_action, - const BubblePositioner* bubble_positioner) - : LocationBarImageView(bubble_positioner), - owner_(owner), + ExtensionAction* page_action) + : owner_(owner), profile_(profile), page_action_(page_action), ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), @@ -1468,19 +1373,17 @@ void LocationBarView::PageActionImageView::ExecuteAction(int button, if (popup_showing) return; - 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()); + gfx::Rect screen_bounds(GetImageBounds()); + gfx::Point origin(screen_bounds.origin()); + View::ConvertPointToScreen(this, &origin); + screen_bounds.set_origin(origin); popup_ = ExtensionPopup::Show( page_action_->GetPopupUrl(current_tab_id_), browser, browser->profile(), browser->window()->GetNativeHandle(), - rect, + screen_bounds, BubbleBorder::TOP_RIGHT, true, // Activate the popup window. inspect_with_devtools, @@ -1493,24 +1396,17 @@ 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 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. + // 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.) return true; } void LocationBarView::PageActionImageView::OnMouseReleased( const views::MouseEvent& event, bool canceled) { - if (canceled) + if (canceled || !HitTest(event.location())) return; int button = -1; @@ -1520,30 +1416,26 @@ void LocationBarView::PageActionImageView::OnMouseReleased( button = 2; } else if (event.IsRightMouseButton()) { // Get the top left point of this button in screen coordinates. - gfx::Point point = gfx::Point(0, 0); - ConvertPointToScreen(this, &point); + gfx::Point menu_origin; + ConvertPointToScreen(this, &menu_origin); // Make the menu appear below the button. - point.Offset(0, height()); + menu_origin.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(point); + context_menu_menu_->RunContextMenuAt(menu_origin); 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 @@ -1572,8 +1464,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_); @@ -1629,6 +1521,54 @@ 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 681a015..48d72f0 100644 --- a/chrome/browser/views/location_bar_view.h +++ b/chrome/browser/views/location_bar_view.h @@ -38,7 +38,6 @@ #endif class Browser; -class BubblePositioner; class CommandUpdater; class ContentSettingImageModel; class ExtensionAction; @@ -57,6 +56,7 @@ class Profile; class LocationBarView : public LocationBar, public LocationBarTesting, public views::View, + public views::DragController, public AutocompleteEditController { public: class Delegate { @@ -76,17 +76,13 @@ 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, - const BubblePositioner* bubble_positioner); + bool popup_window_mode); virtual ~LocationBarView(); void Init(); @@ -97,7 +93,8 @@ class LocationBarView : public LocationBar, // Returns the appropriate color for the desired kind, based on the user's // system theme. - static SkColor GetColor(bool is_secure, ColorKind kind); + static SkColor GetColor(ToolbarModel::SecurityLevel security_level, + 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 @@ -121,6 +118,12 @@ 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(); @@ -158,6 +161,15 @@ 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; @@ -172,6 +184,9 @@ 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(); } @@ -190,20 +205,100 @@ class LocationBarView : public LocationBar, void Focus(); private: - // 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 { + // 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 SelectedKeywordView(Profile* profile); - virtual ~SelectedKeywordView(); + 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 { + public: + IconLabelBubbleView(const int background_images[], + int contained_image, + const SkColor& color); + virtual ~IconLabelBubbleView(); 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(); @@ -224,18 +319,16 @@ class LocationBarView : public LocationBar, // deleted out from under us. std::wstring keyword_; - // For painting the background. - views::HorizontalPainter background_painter_; - - // Label containing the complete description. + // 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. views::Label full_label_; - - // Label containing the partial description. views::Label partial_label_; Profile* profile_; - DISALLOW_COPY_AND_ASSIGN(SelectedKeywordView); + DISALLOW_IMPLICIT_CONSTRUCTORS(SelectedKeywordView); }; // KeywordHintView is used to display a hint to the user when the selected @@ -275,96 +368,7 @@ class LocationBarView : public LocationBar, Profile* profile_; - 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); + DISALLOW_IMPLICIT_CONSTRUCTORS(KeywordHintView); }; class ContentSettingImageView : public views::ImageView, @@ -372,8 +376,7 @@ class LocationBarView : public LocationBar, public: ContentSettingImageView(ContentSettingsType content_type, const LocationBarView* parent, - Profile* profile, - const BubblePositioner* bubble_positioner); + Profile* profile); virtual ~ContentSettingImageView(); void set_profile(Profile* profile) { profile_ = profile; } @@ -382,6 +385,7 @@ 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: @@ -400,25 +404,20 @@ 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<ContentSettingImageView*> ContentSettingViews; // PageActionImageView is used to display the icon for a given PageAction // and notify the extension when the icon is clicked. - class PageActionImageView : public LocationBarImageView, + class PageActionImageView : public views::ImageView, public ImageLoadingTracker::Observer, public ExtensionContextMenuModel::PopupDelegate, public ExtensionPopup::Observer { public: PageActionImageView(LocationBarView* owner, Profile* profile, - ExtensionAction* page_action, - const BubblePositioner* bubble_positioner); + ExtensionAction* page_action); virtual ~PageActionImageView(); ExtensionAction* page_action() { return page_action_; } @@ -430,13 +429,9 @@ 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); @@ -497,7 +492,7 @@ class LocationBarView : public LocationBar, // The current popup and the button it came from. NULL if no popup. ExtensionPopup* popup_; - DISALLOW_COPY_AND_ASSIGN(PageActionImageView); + DISALLOW_IMPLICIT_CONSTRUCTORS(PageActionImageView); }; friend class PageActionImageView; @@ -505,11 +500,30 @@ class LocationBarView : public LocationBar, friend class PageActionWithBadgeView; typedef std::vector<PageActionWithBadgeView*> PageActionViews; - // 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); + 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); + }; // Returns the height in pixels of the margin at the top of the bar. int TopMargin() const; @@ -525,25 +539,12 @@ 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(); @@ -555,16 +556,8 @@ class LocationBarView : public LocationBar, // PageActions. void RefreshPageActionViews(); - // 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); + // Sets the visibility of view to new_vis. + void ToggleVisibility(bool new_vis, views::View* view); #if defined(OS_WIN) // Helper for the Mouse event handlers that does all the real work. @@ -609,13 +602,20 @@ 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_, then type_to_search_view_. + // given to the keyword_view_, then hint_view_. + // These autocollapse when the edit needs the room. // Shown if the user has selected a keyword. SelectedKeywordView selected_keyword_view_; @@ -623,20 +623,14 @@ 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_; - // A label displayed after the lock icon to show some extra information. - views::Label info_label_; + // The star. + StarView star_view_; // 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. @@ -645,13 +639,10 @@ class LocationBarView : public LocationBar, // Used schedule a task for the first run info bubble. ScopedRunnableMethodFactory<LocationBarView> 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_COPY_AND_ASSIGN(LocationBarView); + DISALLOW_IMPLICIT_CONSTRUCTORS(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 new file mode 100644 index 0000000..8331db1 --- /dev/null +++ b/chrome/browser/views/pinned_contents_info_bubble.cc @@ -0,0 +1,74 @@ +// 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 new file mode 100644 index 0000000..92477c0 --- /dev/null +++ b/chrome/browser/views/pinned_contents_info_bubble.h @@ -0,0 +1,89 @@ +// 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 ce26ac7..3521a88 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->GetIndexOfTab(source_tab)), + source_model_index_(source_tabstrip->GetModelIndexOfTab(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_->GetTabAt(0); + Tab* first_tab = source_tabstrip_->GetTabAtTabDataIndex(0); views::View::ConvertPointToWidget(first_tab, &first_source_tab_point_); UpdateWindowCreatePoint(); } @@ -963,8 +963,9 @@ gfx::Point DraggedTabController::GetDraggedViewPoint( Tab* DraggedTabController::GetTabMatchingDraggedContents( TabStrip* tabstrip) const { - int index = tabstrip->model()->GetIndexOfTabContents(dragged_contents_); - return index == TabStripModel::kNoTab ? NULL : tabstrip->GetTabAt(index); + int model_index = tabstrip->model()->GetIndexOfTabContents(dragged_contents_); + return model_index == TabStripModel::kNoTab ? + NULL : tabstrip->GetTabAtModelIndex(model_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 b363cb5..f089393 100644 --- a/chrome/browser/views/tabs/tab_renderer.cc +++ b/chrome/browser/views/tabs/tab_renderer.cc @@ -6,6 +6,7 @@ #include <limits> +#include "app/animation_container.h" #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "app/slide_animation.h" @@ -81,9 +82,15 @@ 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; @@ -205,7 +212,7 @@ class TabCloseButton : public views::ImageButton { } private: - DISALLOW_EVIL_CONSTRUCTORS(TabCloseButton); + DISALLOW_COPY_AND_ASSIGN(TabCloseButton); }; } // namespace @@ -246,7 +253,7 @@ class TabRenderer::FavIconCrashAnimation : public Animation, private: TabRenderer* target_; - DISALLOW_EVIL_CONSTRUCTORS(FavIconCrashAnimation); + DISALLOW_COPY_AND_ASSIGN(FavIconCrashAnimation); }; //////////////////////////////////////////////////////////////////////////////// @@ -282,6 +289,10 @@ 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()); @@ -407,6 +418,11 @@ 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); @@ -502,6 +518,15 @@ 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()) @@ -715,45 +740,47 @@ void TabRenderer::PaintInactiveTabBackground(gfx::Canvas* canvas) { int bg_offset_y = GetThemeProvider()->HasCustomImage(tab_id) ? 0 : background_offset_.y(); - // 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); + 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); + } } void TabRenderer::PaintActiveTabBackground(gfx::Canvas* canvas) { @@ -765,33 +792,39 @@ 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_active.l_width, height()); + *tab_bg, offset, 0, tab_image->l_width, height()); SkBitmap theme_l = - SkBitmapOperations::CreateMaskedBitmap(tab_l, *tab_alpha.image_l); + SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l); canvas->DrawBitmapInt(theme_l, 0, 0); // Draw right edge. SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg, - offset + width() - tab_active.r_width, 0, tab_active.r_width, height()); + offset + width() - tab_image->r_width, 0, tab_image->r_width, height()); SkBitmap theme_r = - SkBitmapOperations::CreateMaskedBitmap(tab_r, *tab_alpha.image_r); - canvas->DrawBitmapInt(theme_r, width() - tab_active.r_width, 0); + SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r); + canvas->DrawBitmapInt(theme_r, width() - tab_image->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_active.l_width, kDropShadowHeight, - tab_active.l_width, kDropShadowHeight, - width() - tab_active.l_width - tab_active.r_width, - height() - kDropShadowHeight); + 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); // Now draw the highlights/shadows around the tab edge. - 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); + 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); } void TabRenderer::PaintLoadingAnimation(gfx::Canvas* canvas) { @@ -819,6 +852,47 @@ 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; @@ -844,6 +918,9 @@ bool TabRenderer::ShouldShowCloseBox() const { } double TabRenderer::GetThrobValue() { + if (data_.alpha != 1) + return data_.alpha; + if (pulse_animation_->IsAnimating()) return pulse_animation_->GetCurrentValue() * kHoverOpacity; @@ -892,21 +969,38 @@ 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 2e309c6..fc01a7a 100644 --- a/chrome/browser/views/tabs/tab_renderer.h +++ b/chrome/browser/views/tabs/tab_renderer.h @@ -1,17 +1,19 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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_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; @@ -37,6 +39,11 @@ 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(); @@ -55,10 +62,26 @@ 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); @@ -93,6 +116,9 @@ 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); @@ -158,6 +184,7 @@ 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. @@ -211,7 +238,11 @@ class TabRenderer : public views::View, mini(false), blocked(false), animating_mini_change(false), - phantom(false) { + phantom(false), + app(false), + render_as_new_tab(false), + render_unselected(false), + alpha(1) { } SkBitmap favicon; @@ -224,6 +255,10 @@ 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_; @@ -233,10 +268,13 @@ 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. @@ -260,10 +298,12 @@ class TabRenderer : public views::View, ThemeProvider* theme_provider_; + scoped_refptr<AnimationContainer> container_; + static void InitClass(); static bool initialized_; - DISALLOW_EVIL_CONSTRUCTORS(TabRenderer); + DISALLOW_COPY_AND_ASSIGN(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 1a9edb3..a28ff52b 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -4,12 +4,14 @@ #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" @@ -25,6 +27,7 @@ #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" @@ -54,10 +57,21 @@ using views::DropTargetEvent; -static const int kDefaultAnimationDurationMs = 200; -static const int kResizeLayoutAnimationDurationMs = 200; -static const int kReorderAnimationDurationMs = 200; -static const int kMiniTabAnimationDurationMs = 200; +// 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 kNewTabButtonHOffset = -5; static const int kNewTabButtonVOffset = 5; @@ -81,6 +95,27 @@ static inline int Round(double x) { return static_cast<int>(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 // @@ -124,292 +159,44 @@ class NewTabButton : public views::ImageButton { DISALLOW_COPY_AND_ASSIGN(NewTabButton); }; -/////////////////////////////////////////////////////////////////////////////// -// -// TabAnimation -// -// A base class for all TabStrip animations. -// -class TabStrip::TabAnimation : public AnimationDelegate { - public: - 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; - } +} // namespace - // Overridden from AnimationDelegate: - virtual void AnimationProgressed(const Animation* animation) { - tabstrip_->AnimationLayout(end_unselected_width_); +// AnimationDelegate used when removing a tab. Does the necessary cleanup when +// done. +class TabStrip::RemoveTabDelegate + : public views::BoundsAnimator::OwnedAnimationDelegate { + public: + RemoveTabDelegate(TabStrip* tab_strip, Tab* tab) + : tabstrip_(tab_strip), + tab_(tab) { } virtual void AnimationEnded(const Animation* animation) { - tabstrip_->FinishAnimation(this, layout_on_completion_); - // This object is destroyed now, so we can't do anything else after this. + CompleteRemove(); } virtual void AnimationCanceled(const Animation* animation) { - 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<double>(TabRenderer::GetStandardSize().width()); - if (start_tab_count < end_tab_count && - start_unselected_width_ < standard_tab_width) { - double minimum_tab_width = - static_cast<double>(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: - // 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()); + // 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(); } 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()); + void CompleteRemove() { + if (!tab_->closing()) { + // The tab was added back yet we weren't canceled. This shouldn't happen. + NOTREACHED(); + return; } - double delta = end_unselected_width_ - start_unselected_width_; - return start_unselected_width_ + (delta * animation_.GetCurrentValue()); - } - - virtual void AnimationEnded(const Animation* animation) { - tabstrip_->RemoveTabAt(index_); + tabstrip_->RemoveTab(tab_); 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. @@ -439,293 +226,10 @@ class TabStrip::RemoveTabAnimation : public TabStrip::TabAnimation { #endif } - 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<double>(Tab::GetMiniWidth())); - } else { - return animation_.CurrentValueBetween( - static_cast<double>(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. + TabStrip* tabstrip_; Tab* tab_; - // 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); + DISALLOW_COPY_AND_ASSIGN(RemoveTabDelegate); }; /////////////////////////////////////////////////////////////////////////////// @@ -741,13 +245,14 @@ 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) { + available_width_for_tabs_(-1), + animation_container_(new AnimationContainer()), + ALLOW_THIS_IN_INITIALIZER_LIST(bounds_animator_(this)), + animation_type_(ANIMATION_DEFAULT) { Init(); } TabStrip::~TabStrip() { - active_animation_.reset(NULL); - // TODO(beng): (1031854) Restore this line once XPFrame/VistaFrame are dead. // model_->RemoveObserver(this); @@ -775,36 +280,34 @@ void TabStrip::DestroyDragController() { void TabStrip::DestroyDraggedSourceTab(Tab* tab) { // We could be running an animation that references this Tab. - if (active_animation_.get()) - active_animation_->Stop(); + StopAnimating(true); + // 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. - std::vector<TabData>::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; - } + 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); } - 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 index) { - DCHECK_GE(index, 0); - DCHECK_LT(index, GetTabCount()); - return tab_data_.at(index).ideal_bounds; +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; } Tab* TabStrip::GetSelectedTab() const { - return GetTabAtAdjustForAnimation(model()->selected_index()); + return GetTabAtModelIndex(model()->selected_index()); } void TabStrip::InitTabStripButtons() { @@ -836,7 +339,7 @@ int TabStrip::GetPreferredHeight() { void TabStrip::SetBackgroundOffset(const gfx::Point& offset) { int tab_count = GetTabCount(); for (int i = 0; i < tab_count; ++i) - GetTabAt(i)->SetBackgroundOffset(offset); + GetTabAtTabDataIndex(i)->SetBackgroundOffset(offset); } bool TabStrip::IsPositionInWindowCaption(const gfx::Point& point) { @@ -871,12 +374,10 @@ bool TabStrip::IsDragSessionActive() const { } void TabStrip::UpdateLoadingAnimations() { - 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); + 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); if (!contents || !contents->is_loading()) { current_tab->ValidateLoadingAnimation(Tab::ANIMATION_NONE); } else if (contents->waiting_for_response()) { @@ -884,12 +385,13 @@ void TabStrip::UpdateLoadingAnimations() { } else { current_tab->ValidateLoadingAnimation(Tab::ANIMATION_LOADING); } + model_index++; } } } bool TabStrip::IsAnimating() const { - return active_animation_.get() != NULL; + return bounds_animator_.IsAnimating() || new_tab_timer_.IsRunning(); } TabStrip* TabStrip::AsTabStrip() { @@ -901,6 +403,7 @@ 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. @@ -910,8 +413,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 = GetTabCount() - 1; i >= 0; --i) { - Tab* tab = GetTabAt(i); + for (int i = tab_count - 1; i >= 0; --i) { + Tab* tab = GetTabAtTabDataIndex(i); if (tab->phantom()) tab->ProcessPaint(canvas); } @@ -920,8 +423,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 = GetTabCount() - 1; i >= 0; --i) { - Tab* tab = GetTabAt(i); + for (int i = tab_count - 1; i >= 0; --i) { + Tab* tab = GetTabAtTabDataIndex(i); if (tab->phantom()) { canvas->save(); canvas->ClipRectInt(tab->MirroredX(), tab->y(), tab->width(), @@ -936,14 +439,27 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) { Tab* selected_tab = NULL; - for (int i = GetTabCount() - 1; i >= 0; --i) { - Tab* tab = GetTabAt(i); + for (int i = tab_count - 1; i >= 0; --i) { + Tab* tab = GetTabAtTabDataIndex(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()) { - tab->ProcessPaint(canvas); + 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); + } } else { selected_tab = tab; } @@ -962,23 +478,30 @@ 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. - newtab_button_->ProcessPaint(canvas); + if (animation_type_ != ANIMATION_NEW_TAB_1 && + animation_type_ != ANIMATION_NEW_TAB_2 && + animation_type_ != ANIMATION_NEW_TAB_3) { + 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 GetTabAt(GetTabCount() - 1); + return GetTabAtTabDataIndex(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 GetTabAt(index); + return GetTabAtTabDataIndex(index); } else { return NULL; } @@ -991,22 +514,15 @@ views::View* TabStrip::GetViewByID(int view_id) const { void TabStrip::Layout() { // Called from: // - window resize - // - animation completion - if (active_animation_.get()) - active_animation_->Stop(); + StopAnimating(false); + GenerateIdealBounds(); - int tab_count = GetTabCount(); - int tab_right = 0; - 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<double>(tab_right), current_unselected_width_); + 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_); + SchedulePaint(); } @@ -1015,6 +531,9 @@ 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); } @@ -1085,10 +604,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) ? GetTabAt(i + 1) : NULL; + Tab* next_tab = i < (tab_count - 1) ? GetTabAtTabDataIndex(i + 1) : NULL; if (next_tab && next_tab->IsSelected() && IsPointInTab(next_tab, point)) return next_tab; - Tab* tab = GetTabAt(i); + Tab* tab = GetTabAtTabDataIndex(i); if (IsPointInTab(tab, point)) return tab; } @@ -1117,16 +636,15 @@ void TabStrip::ViewHierarchyChanged(bool is_add, // TabStrip, TabStripModelObserver implementation: void TabStrip::TabInsertedAt(TabContents* contents, - int index, + int model_index, bool foreground) { DCHECK(contents); - DCHECK(index == TabStripModel::kNoTab || model_->ContainsIndex(index)); + DCHECK(model_index == TabStripModel::kNoTab || + model_->ContainsIndex(model_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; @@ -1145,10 +663,23 @@ void TabStrip::TabInsertedAt(TabContents* contents, } // See if we're already in the list. We don't want to add ourselves twice. - std::vector<TabData>::const_iterator iter = tab_data_.begin(); - for (; iter != tab_data_.end() && !contains_tab; ++iter) { - if (iter->tab == tab) - contains_tab = true; + 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); } } @@ -1159,40 +690,43 @@ 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() + index, d); - tab->UpdateData(contents, model_->IsPhantomTab(index), false); + tab_data_.insert(tab_data_.begin() + + ModelIndexToTabDataIndex(model_index), d); + tab->UpdateData(contents, model_->IsPhantomTab(model_index), false); } - tab->set_mini(model_->IsMiniTab(index)); - tab->SetBlocked(model_->IsTabBlocked(index)); + tab->set_mini(model_->IsMiniTab(model_index)); + tab->set_app(model_->IsAppTab(model_index)); + tab->SetBlocked(model_->IsTabBlocked(model_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()) { - StartInsertTabAnimation(index); + if (!IsDragSessionActive() && + ShouldStartIntertTabAnimationAtEnd(model_index, foreground)) { + StartInsertTabAnimationAtEnd(); + } else { + StartInsertTabAnimation(model_index); + } } else { Layout(); } } -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::TabDetachedAt(TabContents* contents, int model_index) { + StartRemoveTabAnimation(model_index); } void TabStrip::TabSelectedAt(TabContents* old_contents, TabContents* new_contents, - int index, + int model_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_; @@ -1202,117 +736,133 @@ void TabStrip::TabSelectedAt(TabContents* old_contents, SchedulePaint(); } - int old_index = model_->GetIndexOfTabContents(old_contents); - if (old_index >= 0) - GetTabAt(old_index)->StopMiniTabTitleAnimation(); + int old_model_index = model_->GetIndexOfTabContents(old_contents); + if (old_model_index >= 0) { + GetTabAtTabDataIndex(ModelIndexToTabDataIndex(old_model_index))-> + StopMiniTabTitleAnimation(); + } } -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::TabMoved(TabContents* contents, + int from_model_index, + int to_model_index) { + StartMoveTabAnimation(from_model_index, to_model_index); } -void TabStrip::TabChangedAt(TabContents* contents, int index, +void TabStrip::TabChangedAt(TabContents* contents, + int model_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 = GetTabAtAdjustForAnimation(index); + Tab* tab = GetTabAtModelIndex(model_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(index), + tab->UpdateData(contents, model_->IsPhantomTab(model_index), change_type == LOADING_ONLY); tab->UpdateFromModel(); } void TabStrip::TabReplacedAt(TabContents* old_contents, TabContents* new_contents, - int index) { - TabChangedAt(new_contents, index, ALL); + int model_index) { + TabChangedAt(new_contents, model_index, ALL); } -void TabStrip::TabMiniStateChanged(TabContents* contents, int index) { - GetTabAt(index)->set_mini(model_->IsMiniTab(index)); +void TabStrip::TabMiniStateChanged(TabContents* contents, int model_index) { + GetTabAtModelIndex(model_index)->set_mini( + model_->IsMiniTab(model_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(index); + StartMiniTabAnimation(); else Layout(); } -void TabStrip::TabBlockedStateChanged(TabContents* contents, int index) { - GetTabAt(index)->SetBlocked(model_->IsTabBlocked(index)); +void TabStrip::TabBlockedStateChanged(TabContents* contents, int model_index) { + GetTabAtModelIndex(model_index)->SetBlocked( + model_->IsTabBlocked(model_index)); } /////////////////////////////////////////////////////////////////////////////// // TabStrip, Tab::Delegate implementation: bool TabStrip::IsTabSelected(const Tab* tab) const { - if (tab->closing()) + if (tab->closing() || tab->render_unselected()) return false; - return GetIndexOfTab(tab) == model_->selected_index(); + return GetModelIndexOfTab(tab) == model_->selected_index(); } bool TabStrip::IsTabPinned(const Tab* tab) const { if (tab->closing()) return false; - return model_->IsTabPinned(GetIndexOfTab(tab)); + return model_->IsTabPinned(GetModelIndexOfTab(tab)); } void TabStrip::SelectTab(Tab* tab) { - int index = GetIndexOfTab(tab); - if (model_->ContainsIndex(index)) - model_->SelectTabContentsAt(index, true); + int model_index = GetModelIndexOfTab(tab); + if (model_->ContainsIndex(model_index)) + model_->SelectTabContentsAt(model_index, true); } void TabStrip::CloseTab(Tab* tab) { - int tab_index = GetIndexOfTab(tab); - if (model_->ContainsIndex(tab_index)) { - TabContents* contents = model_->GetTabContentsAt(tab_index); + int model_index = GetModelIndexOfTab(tab); + if (model_->ContainsIndex(model_index)) { + TabContents* contents = model_->GetTabContentsAt(model_index); if (contents) UserMetrics::RecordAction(UserMetricsAction("CloseTab_Mouse"), contents->profile()); - 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(); + 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(); + } // Note that the next call might not close the tab (because of unload // hanlders or if the delegate veto the close). - model_->CloseTabContentsAt(tab_index); + model_->CloseTabContentsAt(model_index); } } bool TabStrip::IsCommandEnabledForTab( TabStripModel::ContextMenuCommand command_id, const Tab* tab) const { - int index = GetIndexOfTab(tab); - if (model_->ContainsIndex(index)) - return model_->IsContextMenuCommandEnabled(index, command_id); + int model_index = GetModelIndexOfTab(tab); + if (model_->ContainsIndex(model_index)) + return model_->IsContextMenuCommandEnabled(model_index, command_id); return false; } void TabStrip::ExecuteCommandForTab( TabStripModel::ContextMenuCommand command_id, Tab* tab) { - int index = GetIndexOfTab(tab); - if (model_->ContainsIndex(index)) - model_->ExecuteContextMenuCommand(index, command_id); + 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(); } void TabStrip::StartHighlightTabsForCommand( @@ -1320,13 +870,13 @@ void TabStrip::StartHighlightTabsForCommand( if (command_id == TabStripModel::CommandCloseTabsOpenedBy || command_id == TabStripModel::CommandCloseOtherTabs || command_id == TabStripModel::CommandCloseTabsToRight) { - int index = GetIndexOfTab(tab); - if (model_->ContainsIndex(index)) { + int model_index = GetModelIndexOfTab(tab); + if (model_->ContainsIndex(model_index)) { std::vector<int> indices = - model_->GetIndicesClosedByCommand(index, command_id); + model_->GetIndicesClosedByCommand(model_index, command_id); for (std::vector<int>::const_iterator i = indices.begin(); i != indices.end(); ++i) { - GetTabAtAdjustForAnimation(*i)->StartPulse(); + GetTabAtModelIndex(*i)->StartPulse(); } } } @@ -1344,7 +894,7 @@ void TabStrip::StopHighlightTabsForCommand( void TabStrip::StopAllHighlighting() { for (int i = 0; i < GetTabCount(); ++i) - GetTabAt(i)->StopPulse(); + GetTabAtTabDataIndex(i)->StopPulse(); } void TabStrip::MaybeStartDrag(Tab* tab, const views::MouseEvent& event) { @@ -1354,8 +904,8 @@ void TabStrip::MaybeStartDrag(Tab* tab, const views::MouseEvent& event) { // the user is dragging. if (IsAnimating() || tab->closing() || !HasAvailableDragActions()) return; - int index = GetIndexOfTab(tab); - if (!model_->ContainsIndex(index)) { + int model_index = GetModelIndexOfTab(tab); + if (!model_->ContainsIndex(model_index)) { CHECK(false); return; } @@ -1463,15 +1013,18 @@ void TabStrip::DidProcessEvent(GdkEvent* event) { void TabStrip::Init() { SetID(VIEW_ID_TAB_STRIP); model_->AddObserver(this); - newtab_button_size_.SetSize(kNewTabButtonWidth, kNewTabButtonHeight); - if (browser_defaults::kSizeTabButtonToTopOfTabStrip) - newtab_button_size_.set_height(kNewTabButtonHeight + kNewTabButtonVOffset); + newtab_button_bounds_.SetRect(0, 0, kNewTabButtonWidth, kNewTabButtonHeight); + if (browser_defaults::kSizeTabButtonToTopOfTabStrip) { + newtab_button_bounds_.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() { @@ -1501,20 +1054,14 @@ void TabStrip::LoadNewTabButtonImage() { delete tp; } -Tab* TabStrip::GetTabAt(int index) const { - DCHECK_GE(index, 0); - DCHECK_LT(index, GetTabCount()); - return tab_data_.at(index).tab; +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::GetTabAtAdjustForAnimation(int index) const { - if (active_animation_.get() && - active_animation_->type() == TabAnimation::REMOVE && - index >= - static_cast<RemoveTabAnimation*>(active_animation_.get())->index()) { - index++; - } - return GetTabAt(index); +Tab* TabStrip::GetTabAtModelIndex(int model_index) const { + return GetTabAtTabDataIndex(ModelIndexToTabDataIndex(model_index)); } int TabStrip::GetTabCount() const { @@ -1547,7 +1094,7 @@ void TabStrip::GetDesiredTabWidths(int tab_count, int available_width; if (available_width_for_tabs_ < 0) { available_width = width(); - available_width -= (kNewTabButtonHOffset + newtab_button_size_.width()); + available_width -= (kNewTabButtonHOffset + newtab_button_bounds_.width()); } else { // Interesting corner case: if |available_width_for_tabs_| > the result // of the calculation in the conditional arm above, the strip is in @@ -1607,14 +1154,6 @@ 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 @@ -1635,7 +1174,7 @@ void TabStrip::ResizeLayoutTabs() { // mini-tabs have the same width), so there is nothing to do. return; } - Tab* first_tab = GetTabAt(mini_tab_count); + Tab* first_tab = GetTabAtTabDataIndex(mini_tab_count); double unselected, selected; GetDesiredTabWidths(GetTabCount(), mini_tab_count, &unselected, &selected); int w = Round(first_tab->IsSelected() ? selected : selected); @@ -1657,7 +1196,7 @@ bool TabStrip::IsCursorInTabStripZone() const { DWORD pos = GetMessagePos(); gfx::Point cursor_point(pos); #elif defined(OS_LINUX) - // TODO: make sure this is right with multiple monitors. + // TODO(sky): make sure this is right with multiple monitors. GdkScreen* screen = gdk_screen_get_default(); GdkDisplay* display = gdk_screen_get_display(screen); gint x, y; @@ -1688,14 +1227,13 @@ gfx::Rect TabStrip::GetDropBounds(int drop_index, DCHECK(drop_index != -1); int center_x; if (drop_index < GetTabCount()) { - Tab* tab = GetTabAt(drop_index); - // TODO(sky): update these for mini-tabs. + Tab* tab = GetTabAtTabDataIndex(drop_index); if (drop_before) center_x = tab->x() - (kTabHOffset / 2); else center_x = tab->x() + (tab->width() / 2); } else { - Tab* last_tab = GetTabAt(drop_index - 1); + Tab* last_tab = GetTabAtTabDataIndex(drop_index - 1); center_x = last_tab->x() + last_tab->width() + (kTabHOffset / 2); } @@ -1731,7 +1269,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 = GetTabAt(i); + Tab* tab = GetTabAtTabDataIndex(i); const int tab_max_x = tab->x() + tab->width(); const int hot_width = tab->width() / 3; if (x < tab_max_x) { @@ -1749,25 +1287,26 @@ void TabStrip::UpdateDropIndex(const DropTargetEvent& event) { SetDropIndex(GetTabCount(), true); } -void TabStrip::SetDropIndex(int index, bool drop_before) { - if (index == -1) { +void TabStrip::SetDropIndex(int tab_data_index, bool drop_before) { + if (tab_data_index == -1) { if (drop_info_.get()) drop_info_.reset(NULL); return; } - if (drop_info_.get() && drop_info_->drop_index == index && + if (drop_info_.get() && drop_info_->drop_index == tab_data_index && drop_info_->drop_before == drop_before) { return; } bool is_beneath; - gfx::Rect drop_bounds = GetDropBounds(index, drop_before, &is_beneath); + gfx::Rect drop_bounds = GetDropBounds(tab_data_index, drop_before, + &is_beneath); if (!drop_info_.get()) { - drop_info_.reset(new DropInfo(index, drop_before, !is_beneath)); + drop_info_.reset(new DropInfo(tab_data_index, drop_before, !is_beneath)); } else { - drop_info_->drop_index = index; + drop_info_->drop_index = tab_data_index; drop_info_->drop_before = drop_before; if (is_beneath == drop_info_->point_down) { drop_info_->point_down = !is_beneath; @@ -1844,8 +1383,19 @@ 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(tab_count, GetMiniTabCount(), &unselected, &selected); + GetDesiredTabWidths(non_closing_tab_count, mini_tab_count, &unselected, + &selected); current_unselected_width_ = unselected; current_selected_width_ = selected; @@ -1854,139 +1404,259 @@ 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) { - 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, + 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_height); - tab_data_.at(i).ideal_bounds = state; - tab_x = end_of_tab + GetTabHOffset(i + 1); + tab_x = end_of_tab + kTabHOffset; + last_was_mini = tab->mini(); + } } -} -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 ? + // Update bounds of new tab button. + int new_tab_x; + int new_tab_y = browser_defaults::kSizeTabButtonToTopOfTabStrip ? 0 : kNewTabButtonVOffset; - if (delta > 1 && !needs_resize_layout_) { + if (abs(Round(unselected) - Tab::GetStandardSize().width()) > 1 && + available_width_for_tabs_ == -1) { // 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. - newtab_button_->SetBounds(width() - newtab_button_size_.width(), - v_offset, - newtab_button_size_.width(), - newtab_button_size_.height()); + new_tab_x = width() - newtab_button_bounds_.width(); } else { - newtab_button_->SetBounds( - Round(last_tab_right - kTabHOffset) + kNewTabButtonHOffset, - v_offset, newtab_button_size_.width(), newtab_button_size_.height()); + new_tab_x = Round(tab_x - kTabHOffset) + kNewTabButtonHOffset; } + newtab_button_bounds_.set_origin(gfx::Point(new_tab_x, new_tab_y)); } -// 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::NewTabAnimation1Done() { + int tab_data_index = static_cast<int>(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); + } +} + +bool TabStrip::ShouldStartIntertTabAnimationAtEnd(int model_index, + bool foreground) { + return foreground && (model_index + 1 == model_->count()) && + (model_->GetTabContentsAt(model_index)->GetURL() == + GURL(chrome::kChromeUINewTabURL)); } void TabStrip::StartResizeLayoutAnimation() { - if (active_animation_.get()) - active_animation_->Stop(); - active_animation_.reset(new ResizeLayoutAnimation(this)); - active_animation_->Start(); + ResetAnimationState(true); + GenerateIdealBounds(); + AnimateToIdealBounds(); } -void TabStrip::StartInsertTabAnimation(int index) { +void TabStrip::StartInsertTabAnimationAtEnd() { + ResetAnimationState(true); + // The TabStrip can now use its entire width to lay out Tabs. available_width_for_tabs_ = -1; - if (active_animation_.get()) - active_animation_->Stop(); - active_animation_.reset(new InsertTabAnimation(this, index)); - active_animation_->Start(); + + 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); } -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(); +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()); } - active_animation_.reset(new RemoveTabAnimation(this, index, contents)); - active_animation_->Start(); + + AnimateToIdealBounds(); } -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::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::StartMiniTabAnimation(int index) { - if (active_animation_.get()) - active_animation_->Stop(); - active_animation_.reset(new MiniTabAnimation(this, 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::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::StartMiniTabAnimation() { + ResetAnimationState(true); + + GenerateIdealBounds(); + AnimateToIdealBounds(); } -void TabStrip::FinishAnimation(TabStrip::TabAnimation* animation, - bool layout) { - active_animation_.reset(NULL); +void TabStrip::StopAnimating(bool layout) { + if (!IsAnimating()) + return; + + new_tab_timer_.Stop(); - // Reset the animation state of each tab. - for (int i = 0, count = GetTabCount(); i < count; ++i) - GetTabAt(i)->set_animating_mini_change(false); + if (bounds_animator_.IsAnimating()) { + // Cancelling the animation triggers OnBoundsAnimatorDone, which invokes + // ResetAnimationState. + bounds_animator_.Cancel(); + } else { + ResetAnimationState(false); + } + + DCHECK(!IsAnimating()); if (layout) Layout(); } -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; - } +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); } - return -1; } int TabStrip::GetMiniTabCount() const { @@ -2011,22 +1681,21 @@ bool TabStrip::IsPointInTab(Tab* tab, return tab->HitTest(point_in_tab_coords); } -void TabStrip::RemoveTabAt(int index) { - Tab* removed = tab_data_.at(index).tab; +void TabStrip::RemoveTab(Tab* tab) { + int tab_data_index = TabDataIndexOfTab(tab); + + DCHECK(tab_data_index != -1); // Remove the Tab from the TabStrip's list... - tab_data_.erase(tab_data_.begin() + index); + tab_data_.erase(tab_data_.begin() + tab_data_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(removed)) { - removed->GetParent()->RemoveChildView(removed); - delete removed; - } - GenerateIdealBounds(); + if (!IsDragSessionActive() || !drag_controller_->IsDragSourceTab(tab)) + delete tab; } void TabStrip::HandleGlobalMouseMoveEvent() { @@ -2049,8 +1718,40 @@ void TabStrip::HandleGlobalMouseMoveEvent() { bool TabStrip::HasPhantomTabs() const { for (int i = 0; i < GetTabCount(); ++i) { - if (GetTabAt(i)->phantom()) + if (GetTabAtTabDataIndex(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 af6cc34..e1cbfda 100644 --- a/chrome/browser/views/tabs/tab_strip.h +++ b/chrome/browser/views/tabs/tab_strip.h @@ -5,11 +5,16 @@ #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; @@ -42,7 +47,8 @@ class TabStrip : public BaseTabStrip, public TabStripModelObserver, public Tab::TabDelegate, public views::ButtonListener, - public MessageLoopForUI::Observer { + public MessageLoopForUI::Observer, + public views::BoundsAnimatorObserver { public: explicit TabStrip(TabStripModel* model); virtual ~TabStrip(); @@ -62,7 +68,7 @@ class TabStrip : public BaseTabStrip, void DestroyDraggedSourceTab(Tab* tab); // Retrieves the ideal bounds for the Tab at the specified index. - gfx::Rect GetIdealBounds(int index); + gfx::Rect GetIdealBounds(int tab_data_index); // Returns the currently selected tab. Tab* GetSelectedTab() const; @@ -103,6 +109,9 @@ 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(); @@ -114,21 +123,24 @@ class TabStrip : public BaseTabStrip, // TabStripModelObserver implementation: virtual void TabInsertedAt(TabContents* contents, - int index, + int model_index, bool foreground); - virtual void TabDetachedAt(TabContents* contents, int index); + virtual void TabDetachedAt(TabContents* contents, int model_index); virtual void TabSelectedAt(TabContents* old_contents, TabContents* contents, - int index, + int model_index, bool user_gesture); - virtual void TabMoved(TabContents* contents, int from_index, int to_index); - virtual void TabChangedAt(TabContents* contents, int index, + virtual void TabMoved(TabContents* contents, + int from_model_index, + int to_model_index); + virtual void TabChangedAt(TabContents* contents, + int model_index, TabChangeType change_type); virtual void TabReplacedAt(TabContents* old_contents, TabContents* new_contents, - int index); - virtual void TabMiniStateChanged(TabContents* contents, int index); - virtual void TabBlockedStateChanged(TabContents* contents, int index); + int model_index); + virtual void TabMiniStateChanged(TabContents* contents, int model_index); + virtual void TabBlockedStateChanged(TabContents* contents, int model_index); // Tab::Delegate implementation: virtual bool IsTabSelected(const Tab* tab) const; @@ -165,22 +177,70 @@ class TabStrip : public BaseTabStrip, static const int mini_to_non_mini_gap_; private: - class InsertTabAnimation; - class MiniMoveAnimation; - class MiniTabAnimation; - class MoveTabAnimation; - class RemoveTabAnimation; - class ResizeLayoutAnimation; - class TabAnimation; + class RemoveTabDelegate; friend class DraggedTabController; - friend class InsertTabAnimation; - friend class MiniMoveAnimation; - friend class MiniTabAnimation; - friend class MoveTabAnimation; - friend class RemoveTabAnimation; - friend class ResizeLayoutAnimation; - friend class TabAnimation; + + // 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; + }; TabStrip(); void Init(); @@ -188,9 +248,9 @@ class TabStrip : public BaseTabStrip, // Set the images for the new tab button. void LoadNewTabButtonImage(); - // Retrieves the Tab at the specified index. Take care in using this, you may - // need to use GetTabAtAdjustForAnimation. - Tab* GetTabAt(int index) const; + // 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; // 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 @@ -198,10 +258,13 @@ class TabStrip : public BaseTabStrip, // do not line up with the indices of the view. This method adjusts the index // accordingly. // - // Use this instead of GetTabAt if the index comes from the model. - Tab* GetTabAtAdjustForAnimation(int index) const; + // Use this instead of GetTabAtTabDataIndex if the index comes from the model. + Tab* GetTabAtModelIndex(int model_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. @@ -224,9 +287,6 @@ 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(); @@ -250,7 +310,7 @@ class TabStrip : public BaseTabStrip, void UpdateDropIndex(const views::DropTargetEvent& event); // Sets the location of the drop, repainting as necessary. - void SetDropIndex(int index, bool drop_before); + void SetDropIndex(int tab_data_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. @@ -268,32 +328,38 @@ class TabStrip : public BaseTabStrip, // stable representations of Tab positions. void GenerateIdealBounds(); - // 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); + // 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(); - // A generic Layout method for various classes of TabStrip animations, - // including Insert, Remove and Resize Layout cases/ - void AnimationLayout(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); // Starts various types of TabStrip animations. void StartResizeLayoutAnimation(); - 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; + 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); // Calculates the available width for tabs, assuming a Tab is to be closed. int GetAvailableWidthForTabs(Tab* last_tab) const; @@ -302,9 +368,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 at the specified |index|. This is - // called from the tab animation code and is not a general-purpose method. - void RemoveTabAt(int index); + // 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); // Called from the message loop observer when a mouse movement has occurred // anywhere over our containing window. @@ -313,6 +379,19 @@ 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. @@ -331,7 +410,9 @@ class TabStrip : public BaseTabStrip, // The "New Tab" button. views::ImageButton* newtab_button_; - gfx::Size newtab_button_size_; + + // Ideal bounds of the new tab button. + gfx::Rect newtab_button_bounds_; // 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 @@ -359,37 +440,6 @@ 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<DropInfo> drop_info_; @@ -397,15 +447,19 @@ class TabStrip : public BaseTabStrip, // the drag session. scoped_ptr<DraggedTabController> drag_controller_; - // The Tabs we contain, and their last generated "good" bounds. - struct TabData { - Tab* tab; - gfx::Rect ideal_bounds; - }; std::vector<TabData> tab_data_; - // The currently running animation. - scoped_ptr<TabAnimation> active_animation_; + // To ensure all tabs pulse at the same time they share the same animation + // container. This is that animation container. + scoped_refptr<AnimationContainer> animation_container_; + + views::BoundsAnimator bounds_animator_; + + // Used for stage 1 of new tab animation. + base::OneShotTimer<TabStrip> new_tab_timer_; + + // Set for special animations. + AnimationType animation_type_; DISALLOW_COPY_AND_ASSIGN(TabStrip); }; diff --git a/chrome/browser/views/toolbar_star_toggle.cc b/chrome/browser/views/toolbar_star_toggle.cc deleted file mode 100644 index 710d6fa..0000000 --- a/chrome/browser/views/toolbar_star_toggle.cc +++ /dev/null @@ -1,133 +0,0 @@ -// 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 deleted file mode 100644 index 4966655..0000000 --- a/chrome/browser/views/toolbar_star_toggle.h +++ /dev/null @@ -1,85 +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_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 51c405d..b5ba4cc 100644 --- a/chrome/browser/views/toolbar_view.cc +++ b/chrome/browser/views/toolbar_view.cc @@ -4,42 +4,20 @@ #include "chrome/browser/views/toolbar_view.h" -#include <algorithm> -#include <string> - -#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/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/view_ids.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" @@ -47,12 +25,7 @@ #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" @@ -82,9 +55,8 @@ ToolbarView::ToolbarView(Browser* browser) : model_(browser->toolbar_model()), back_(NULL), forward_(NULL), - reload_(NULL), home_(NULL), - star_(NULL), + reload_(NULL), location_bar_(NULL), go_(NULL), browser_actions_(NULL), @@ -100,9 +72,8 @@ 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_RELOAD, this); browser_->command_updater()->AddCommandObserver(IDC_HOME, this); - browser_->command_updater()->AddCommandObserver(IDC_BOOKMARK_PAGE, this); + browser_->command_updater()->AddCommandObserver(IDC_RELOAD, this); if (browser->type() == Browser::TYPE_NORMAL) display_mode_ = DISPLAYMODE_NORMAL; else @@ -296,14 +267,11 @@ 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_BOOKMARK_PAGE: - button = star_; + case IDC_RELOAD: + button = reload_; break; } if (button) @@ -313,8 +281,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: @@ -337,30 +305,6 @@ void ToolbarView::ButtonPressed( } //////////////////////////////////////////////////////////////////////////////// -// 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, @@ -456,11 +400,12 @@ gfx::Size ToolbarView::GetPreferredSize() { if (IsDisplayModeNormal()) { int min_width = kControlIndent + back_->GetPreferredSize().width() + forward_->GetPreferredSize().width() + kControlHorizOffset + - reload_->GetPreferredSize().width() + (show_home_button_.GetValue() ? - (home_->GetPreferredSize().width() + kControlHorizOffset) : 0) + - star_->GetPreferredSize().width() + go_->GetPreferredSize().width() + - kMenuButtonOffset + + (show_home_button_.GetValue() ? + (home_->GetPreferredSize().width() + kControlHorizOffset) : 0) + + reload_->GetPreferredSize().width() + browser_actions_->GetPreferredSize().width() + + go_->GetPreferredSize().width() + + kMenuButtonOffset + (bookmark_menu_ ? bookmark_menu_->GetPreferredSize().width() : 0) + page_menu_->GetPreferredSize().width() + app_menu_->GetPreferredSize().width() + kPaddingRight; @@ -515,21 +460,18 @@ 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(reload_->x() + reload_->width() + kControlHorizOffset, + home_->SetBounds(forward_->x() + forward_->width() + kControlHorizOffset, child_y, home_->GetPreferredSize().width(), child_height); } else { home_->SetVisible(false); - home_->SetBounds(reload_->x() + reload_->width(), child_y, 0, child_height); + home_->SetBounds(forward_->x() + forward_->width(), child_y, 0, + child_height); } - star_->SetBounds(home_->x() + home_->width() + kControlHorizOffset, - child_y, star_->GetPreferredSize().width(), child_height); + reload_->SetBounds(home_->x() + home_->width() + kControlHorizOffset, child_y, + reload_->GetPreferredSize().width(), child_height); int go_button_width = go_->GetPreferredSize().width(); int browser_actions_width = browser_actions_->GetPreferredSize().width(); @@ -537,7 +479,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 = star_->x() + star_->width(); + int location_x = reload_->x() + reload_->width(); int available_width = width() - kPaddingRight - bookmark_menu_width - app_menu_width - page_menu_width - browser_actions_width - kMenuButtonOffset - go_button_width - location_x; @@ -604,51 +546,6 @@ 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 { @@ -675,12 +572,6 @@ 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); @@ -693,22 +584,19 @@ void ToolbarView::CreateLeftSideControls() { AddChildView(back_); AddChildView(forward_); - AddChildView(reload_); AddChildView(home_); } void ToolbarView::CreateCenterStack(Profile *profile) { - star_ = new ToolbarStarToggle(this); - star_->SetDragController(this); - star_->set_profile(profile); - star_->set_host_view(this); - star_->set_bubble_positioner(this); - star_->Init(); + 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); location_bar_ = new LocationBarView(profile, browser_->command_updater(), model_, this, - display_mode_ == DISPLAYMODE_LOCATION, - this); + display_mode_ == DISPLAYMODE_LOCATION); // The Go button. go_ = new GoButton(location_bar_, browser_); @@ -717,7 +605,7 @@ void ToolbarView::CreateCenterStack(Profile *profile) { LoadCenterStackImages(); - AddChildView(star_); + AddChildView(reload_); location_bar_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_LOCATION)); AddChildView(location_bar_); location_bar_->Init(); @@ -779,15 +667,6 @@ 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, @@ -797,13 +676,20 @@ 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 62faebf..6e45799 100644 --- a/chrome/browser/views/toolbar_view.h +++ b/chrome/browser/views/toolbar_view.h @@ -11,7 +11,6 @@ #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" @@ -27,7 +26,6 @@ class BrowserActionsContainer; class Browser; class Profile; -class ToolbarStarToggle; namespace views { class Menu2; @@ -36,14 +34,12 @@ 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 BubblePositioner { + public views::ButtonListener { public: explicit ToolbarView(Browser* browser); virtual ~ToolbarView(); @@ -86,7 +82,6 @@ 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_; } @@ -115,9 +110,6 @@ 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, @@ -138,17 +130,6 @@ 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; @@ -198,9 +179,8 @@ class ToolbarView : public AccessibleToolbarView, // Controls views::ImageButton* back_; views::ImageButton* forward_; - views::ImageButton* reload_; views::ImageButton* home_; - ToolbarStarToggle* star_; + views::ImageButton* reload_; 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 5f82832..3d275d4 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 set the URL with - // username:password and escaped path and query. + // Because the url_field_ is user-editable, we don't strip anything. std::wstring formatted = net::FormatUrl(url_table_model_->GetURL(selection), - languages, false, UnescapeRule::NONE, NULL, NULL, NULL); + languages, net::kFormatUrlOmitNothing, UnescapeRule::NONE, NULL, NULL, + NULL); url_field_->SetText(formatted); GetDialogClientView()->UpdateDialogButtons(); } |