• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
commit_on_mouse_up()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.
tab_contents()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|.
is_active()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.
is_displayable()147   bool is_displayable() const { return displayable_loader_ != NULL; }
148 
149   // Returns the transition type of the last AutocompleteMatch passed to Update.
last_transition_type()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