Home | History | Annotate | Download | only in instant
      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