1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_ 6 #define CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_ 7 #pragma once 8 9 #include <set> 10 #include <string> 11 12 #include "base/basictypes.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/scoped_vector.h" 15 #include "base/string16.h" 16 #include "base/task.h" 17 #include "base/timer.h" 18 #include "chrome/browser/instant/instant_commit_type.h" 19 #include "chrome/browser/instant/instant_loader_delegate.h" 20 #include "chrome/browser/search_engines/template_url_id.h" 21 #include "chrome/common/instant_types.h" 22 #include "content/common/page_transition_types.h" 23 #include "googleurl/src/gurl.h" 24 #include "ui/gfx/native_widget_types.h" 25 #include "ui/gfx/rect.h" 26 27 struct AutocompleteMatch; 28 class InstantDelegate; 29 class InstantLoader; 30 class InstantLoaderManager; 31 class InstantTest; 32 class PrefService; 33 class Profile; 34 class TabContents; 35 class TabContentsWrapper; 36 class TemplateURL; 37 38 // InstantController maintains a TabContents that is intended to give a preview 39 // of a URL. InstantController is owned by Browser. 40 // 41 // At any time the TabContents maintained by InstantController may be destroyed 42 // by way of |DestroyPreviewContents|, which results in |HideInstant| being 43 // invoked on the delegate. Similarly the preview may be committed at any time 44 // by invoking |CommitCurrentPreview|, which results in |CommitInstant| 45 // being invoked on the delegate. 46 class InstantController : public InstantLoaderDelegate { 47 public: 48 // Amount of time to wait before starting the instant animation. 49 static const int kAutoCommitPauseTimeMS = 1000; 50 // Duration of the instant animation in which the colors change. 51 static const int kAutoCommitFadeInTimeMS = 300; 52 53 InstantController(Profile* profile, InstantDelegate* delegate); 54 ~InstantController(); 55 56 // Registers instant related preferences. 57 static void RegisterUserPrefs(PrefService* prefs); 58 59 // Records instant metrics. 60 static void RecordMetrics(Profile* profile); 61 62 // Returns true if instant is enabled. 63 static bool IsEnabled(Profile* profile); 64 65 // Enables instant. 66 static void Enable(Profile* profile); 67 68 // Disables instant. 69 static void Disable(Profile* profile); 70 71 // Accepts the currently showing instant preview, if any, and returns true. 72 // Returns false if there is no instant preview showing. 73 static bool CommitIfCurrent(InstantController* controller); 74 75 // Invoked as the user types in the omnibox with the url to navigate to. If 76 // the url is empty and there is a preview TabContents it is destroyed. If url 77 // is non-empty and the preview TabContents has not been created it is 78 // created. If |verbatim| is true search results are shown for |user_text| 79 // rather than the best guess as to what the search thought the user meant. 80 // |verbatim| only matters if the AutocompleteMatch is for a search engine 81 // that supports instant. 82 void Update(TabContentsWrapper* tab_contents, 83 const AutocompleteMatch& match, 84 const string16& user_text, 85 bool verbatim, 86 string16* suggested_text); 87 88 // Sets the bounds of the omnibox (in screen coordinates). The bounds are 89 // remembered until the preview is committed or destroyed. This is only used 90 // when showing results for a search provider that supports instant. 91 void SetOmniboxBounds(const gfx::Rect& bounds); 92 93 // Destroys the preview TabContents. Does nothing if the preview TabContents 94 // has not been created. 95 void DestroyPreviewContents(); 96 97 // Destroys the current loaders but remains active. 98 void DestroyPreviewContentsAndLeaveActive(); 99 100 // Returns true if we're showing the last URL passed to |Update|. If this is 101 // false a commit does not result in committing the last url passed to update. 102 // A return value of false happens if we're in the process of determining if 103 // the page supports instant. 104 bool IsCurrent(); 105 106 // Invoked when the user does some gesture that should trigger making the 107 // current previewed page the permanent page. 108 void CommitCurrentPreview(InstantCommitType type); 109 110 // Sets InstantController so that when the mouse is released the preview is 111 // committed. 112 void SetCommitOnMouseUp(); 113 114 bool commit_on_mouse_up() const { return commit_on_mouse_up_; } 115 116 // Returns true if the mouse is down as the result of activating the preview 117 // content. 118 bool IsMouseDownFromActivate(); 119 120 // The autocomplete edit that was initiating the current instant session has 121 // lost focus. Commit or discard the preview accordingly. 122 void OnAutocompleteLostFocus(gfx::NativeView view_gaining_focus); 123 124 // Releases the preview TabContents passing ownership to the caller. This is 125 // intended to be called when the preview TabContents is committed. This does 126 // not notify the delegate. 127 // WARNING: be sure and invoke CompleteRelease after adding the returned 128 // TabContents to a tabstrip. 129 TabContentsWrapper* ReleasePreviewContents(InstantCommitType type); 130 131 // Does cleanup after the preview contents has been added to the tabstrip. 132 // Invoke this if you explicitly invoke ReleasePreviewContents. 133 void CompleteRelease(TabContents* tab); 134 135 // TabContents the match is being shown for. 136 TabContentsWrapper* tab_contents() const { return tab_contents_; } 137 138 // The preview TabContents; may be null. 139 TabContentsWrapper* GetPreviewContents(); 140 141 // Returns true if |Update| has been invoked without a corresponding call to 142 // |DestroyPreviewContents| or |CommitCurrentPreview|. 143 bool is_active() const { return is_active_; } 144 145 // Returns true if the preview TabContents is ready to be displayed. In some 146 // situations this may return false yet GetPreviewContents() returns non-NULL. 147 bool is_displayable() const { return displayable_loader_ != NULL; } 148 149 // Returns the transition type of the last AutocompleteMatch passed to Update. 150 PageTransition::Type last_transition_type() const { 151 return last_transition_type_; 152 } 153 154 // Returns true if we're showing results from a provider that supports the 155 // instant API. See description of |MightSupportInstant| for how this 156 // differs from actual loading state. 157 bool IsShowingInstant(); 158 159 // Returns true if we're attempting to use the instant API with the last URL 160 // passed to |Update|. The value of this may change if it turns the provider 161 // doesn't really support the instant API. 162 // The value of |IsShowingInstant| indicates whether what is currently 163 // displayed supports instant, whereas this returns the loading state. The 164 // state of |IsShowingInstant| differs when transitioning from a non-search 165 // provider to a search provider that supports instant (or the other way 166 // around). For example, if |Update| is passed www.foo.com, followed by a 167 // search string then this returns true, but |IsShowingInstant| returns false 168 // (until the search provider loads, then both return true). 169 bool MightSupportInstant(); 170 171 // Returns the URL currently being loaded or shown if everything has finished 172 // loading. 173 GURL GetCurrentURL(); 174 175 // InstantLoaderDelegate 176 virtual void InstantStatusChanged(InstantLoader* loader) OVERRIDE; 177 virtual void SetSuggestedTextFor(InstantLoader* loader, 178 const string16& text, 179 InstantCompleteBehavior behavior) OVERRIDE; 180 virtual gfx::Rect GetInstantBounds() OVERRIDE; 181 virtual bool ShouldCommitInstantOnMouseUp() OVERRIDE; 182 virtual void CommitInstantLoader(InstantLoader* loader) OVERRIDE; 183 virtual void InstantLoaderDoesntSupportInstant( 184 InstantLoader* loader) OVERRIDE; 185 virtual void AddToBlacklist(InstantLoader* loader, 186 const GURL& url) OVERRIDE; 187 188 private: 189 friend class InstantTest; 190 191 typedef std::set<std::string> HostBlacklist; 192 193 // Updates |displayable_loader_| and if necessary notifies the delegate. 194 void UpdateDisplayableLoader(); 195 196 // Returns the TabContents of the pending loader (or NULL). This is only used 197 // for testing. 198 TabContentsWrapper* GetPendingPreviewContents(); 199 200 // Returns true if we should update immediately. 201 bool ShouldUpdateNow(TemplateURLID instant_id, const GURL& url); 202 203 // Schedules a delayed update to load the specified url. 204 void ScheduleUpdate(const GURL& url); 205 206 // Invoked from the timer to process the last scheduled url. 207 void ProcessScheduledUpdate(); 208 209 // Does the work of processing a change in the status (ready or 210 // http_status_ok) of a loader. 211 void ProcessInstantStatusChanged(InstantLoader* loader); 212 213 // Callback when the |show_timer_| fires. Invokes 214 // |ProcessInstantStatusChanged| with the appropriate arguments. 215 void ShowTimerFired(); 216 217 // Updates InstantLoaderManager and its current InstantLoader. This is invoked 218 // internally from Update. 219 void UpdateLoader(const TemplateURL* template_url, 220 const GURL& url, 221 PageTransition::Type transition_type, 222 const string16& user_text, 223 bool verbatim, 224 string16* suggested_text); 225 226 // Returns true if a preview should be shown for |match|. If |match| has 227 // a TemplateURL that supports the instant API it is set in |template_url|. 228 bool ShouldShowPreviewFor(const AutocompleteMatch& match, 229 const TemplateURL** template_url); 230 231 // Marks the specified search engine id as not supporting instant. 232 void BlacklistFromInstant(TemplateURLID id); 233 234 // Returns true if the specified id has been blacklisted from supporting 235 // instant. 236 bool IsBlacklistedFromInstant(TemplateURLID id); 237 238 // Clears the set of search engines blacklisted. 239 void ClearBlacklist(); 240 241 // Deletes |loader| after a delay. At the time we determine a site doesn't 242 // want to participate in instant we can't destroy the loader (because 243 // destroying the loader destroys the TabContents and the TabContents is on 244 // the stack). Instead we place the loader in |loaders_to_destroy_| and 245 // schedule a task. 246 void ScheduleDestroy(InstantLoader* loader); 247 248 // Destroys all loaders scheduled for destruction in |ScheduleForDestroy|. 249 void DestroyLoaders(); 250 251 // Returns the TemplateURL to use for the specified AutocompleteMatch, or 252 // NULL if there is no TemplateURL for |match|. 253 const TemplateURL* GetTemplateURL(const AutocompleteMatch& match); 254 255 InstantDelegate* delegate_; 256 257 // The TabContents last passed to |Update|. 258 TabContentsWrapper* tab_contents_; 259 260 // See description above getter for details. 261 bool is_active_; 262 263 // The loader that is ready to be displayed. 264 InstantLoader* displayable_loader_; 265 266 // See description above setter. 267 gfx::Rect omnibox_bounds_; 268 269 // See description above CommitOnMouseUp. 270 bool commit_on_mouse_up_; 271 272 // See description above getter. 273 PageTransition::Type last_transition_type_; 274 275 scoped_ptr<InstantLoaderManager> loader_manager_; 276 277 // The IDs of any search engines that don't support instant. We assume all 278 // search engines support instant, but if we determine an engine doesn't 279 // support instant it is added to this list. The list is cleared out on every 280 // reset/commit. 281 std::set<TemplateURLID> blacklisted_ids_; 282 283 // Timer used to delay calls to |UpdateLoader|. 284 base::OneShotTimer<InstantController> update_timer_; 285 286 // Timer used to delay showing loaders whose status isn't ok. 287 base::OneShotTimer<InstantController> show_timer_; 288 289 // Used by ScheduleForDestroy; see it for details. 290 ScopedRunnableMethodFactory<InstantController> destroy_factory_; 291 292 // URL last pased to ScheduleUpdate. 293 GURL scheduled_url_; 294 295 // List of InstantLoaders to destroy. See ScheduleForDestroy for details. 296 ScopedVector<InstantLoader> loaders_to_destroy_; 297 298 // The set of hosts that we don't use instant with. This is shared across all 299 // instances and only maintained for the current session. 300 static HostBlacklist* host_blacklist_; 301 302 DISALLOW_COPY_AND_ASSIGN(InstantController); 303 }; 304 305 #endif // CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_ 306